/* * TYPELIB * * Copyright 1997 Marcus Meissner * 1999 Rein Klazes * 2000 Francois Jacques * -------------------------------------------------------------------------------------- * Known problems (2000, Francois Jacques) * * - Tested using OLEVIEW (Platform SDK tool) only. * * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are * creating by doing a straight copy of the dispinterface instance and just changing * its typekind. Pointed structures aren't copied - only the address of the pointers. * So when you release the dispinterface, you delete the vtable-interface structures * as well... fortunately, clean up of structures is not implemented. * * - locale stuff is partially implemented but hasn't been tested. * * - imported typelib should be stored together in a linked list instead of having * independant TLBImpLib structures in each ITypeInfo. This way, imported libraries * are just imported once (major optimization) * * - typelib file is still read it's in entirety, but it is released now. * - some garbage is read from function names on some very rare occasion * * -------------------------------------------------------------------------------------- * Known problems left from previous implementation (1999, Rein Klazes) : * * -. Only one format of typelibs is supported * -. Data structures are straightforward, but slow for look-ups. * -. (related) nothing is hashed * -. 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. * -. 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 "config.h" #include #include #include #include #include "winerror.h" #include "winnls.h" /* for PRIMARYLANGID */ #include "winreg.h" /* for HKEY_LOCAL_MACHINE */ #include "wine/obj_base.h" #include "heap.h" #include "ole2disp.h" #include "typelib.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(ole); DECLARE_DEBUG_CHANNEL(typelib); /**************************************************************************** * QueryPathOfRegTypeLib [TYPELIB.14] * * the path is "Classes\Typelib\\.\\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; TRACE("\n"); if (HIWORD(guid)) { sprintf( typelibkey, "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win16", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7], wMaj,wMin,lcid); } else { sprintf(xguid,"",(DWORD)guid); FIXME("(%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 (RegQueryValueA(HKEY_LOCAL_MACHINE,typelibkey,pathname,&plen)) { /* try again without lang specific id */ if (SUBLANGID(lcid)) return QueryPathOfRegTypeLib16(guid,wMaj,wMin,PRIMARYLANGID(lcid),path); FIXME("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 */ { /* don't need to ZeroMemory those arrays since sprintf and RegQueryValue add string termination character on output strings */ HRESULT hr = E_FAIL; DWORD dwPathLen = _MAX_PATH; LCID myLCID = lcid; char szXGUID[80]; char szTypeLibKey[100]; char szPath[dwPathLen]; if ( !HIWORD(guid) ) { sprintf(szXGUID, "", (DWORD) guid); FIXME("(%s,%d,%d,0x%04lx,%p),stub!\n", szXGUID, wMaj, wMin, (DWORD)lcid, path); return E_FAIL; } while (hr != S_OK) { sprintf(szTypeLibKey, "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win32", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7], wMaj, wMin, myLCID); if (RegQueryValueA(HKEY_LOCAL_MACHINE, szTypeLibKey, szPath, &dwPathLen)) { if (!lcid) break; else if (myLCID == lcid) { /* try with sub-langid */ myLCID = SUBLANGID(lcid); } else if ((myLCID == SUBLANGID(lcid)) && myLCID) { /* try with system langid */ myLCID = 0; } else { break; } } else { DWORD len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, dwPathLen, NULL, 0 ); BSTR bstrPath = SysAllocStringLen(NULL,len); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, dwPathLen, bstrPath, len); *path = bstrPath; hr = S_OK; } } if (hr != S_OK) TRACE_(typelib)("%s not found\n", szTypeLibKey); return hr; } /****************************************************************************** * CreateTypeLib [OLEAUT32.160] creates a typelib * * RETURNS * Success: S_OK * Failure: Status */ HRESULT WINAPI CreateTypeLib( SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib ) { FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib); return E_FAIL; } /****************************************************************************** * 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( LPOLESTR szFile, /* [in] Name of file to load from */ ITypeLib** pptLib) /* [out] Pointer to pointer to loaded type library */ { FIXME("(%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, ITypeLib2 **ppTypelib); HRESULT WINAPI LoadTypeLib( const OLECHAR *szFile,/* [in] Name of file to load from */ ITypeLib * *pptLib) /* [out] Pointer to pointer to loaded type library */ { TRACE("\n"); return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib); } /****************************************************************************** * LoadTypeLibEx [OLEAUT32.183] * Loads and optionally registers a type library * * RETURNS * Success: S_OK * Failure: Status */ HRESULT WINAPI LoadTypeLibEx( LPCOLESTR szFile, /* [in] Name of file to load from */ REGKIND regkind, /* [in] Specify kind of registration */ ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */ { LPSTR p; HRESULT res; TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib); p=HEAP_strdupWtoA(GetProcessHeap(),0,szFile); res= TLB_ReadTypeLib(p, (ITypeLib2**)pptLib); if (SUCCEEDED(res)) switch(regkind) { case REGKIND_DEFAULT: /* FIXME: is this correct? */ if (!p || !p[0] || (p[0] != '\\' && p[0] != '/' && p[1] != ':')) break; /* else fall-through */ case REGKIND_REGISTER: /* FIXME: Help path? */ if (!SUCCEEDED(res = RegisterTypeLib(*pptLib, (LPOLESTR)szFile, NULL))) { IUnknown_Release(*pptLib); *pptLib = 0; } break; case REGKIND_NONE: break; } HeapFree(GetProcessHeap(),0,p); TRACE(" returns %08lx\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); } TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), 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*/ { HRESULT res; TLIBATTR *attr; OLECHAR guid[80]; LPSTR guidA; CHAR keyName[120]; HKEY key, subKey; if (ptlib == NULL || szFullPath == NULL) return E_INVALIDARG; if (!SUCCEEDED(ITypeLib_GetLibAttr(ptlib, &attr))) return E_FAIL; StringFromGUID2(&attr->guid, guid, 80); guidA = HEAP_strdupWtoA(GetProcessHeap(), 0, guid); snprintf(keyName, sizeof(keyName), "TypeLib\\%s\\%x.%x", guidA, attr->wMajorVerNum, attr->wMinorVerNum); HeapFree(GetProcessHeap(), 0, guidA); res = S_OK; if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { LPOLESTR doc; if (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL))) { if (RegSetValueExW(key, NULL, 0, REG_SZ, (BYTE *)doc, lstrlenW(doc) * sizeof(OLECHAR)) != ERROR_SUCCESS) res = E_FAIL; SysFreeString(doc); } else res = E_FAIL; /* FIXME: This *seems* to be 0 always, not sure though */ if (res == S_OK && RegCreateKeyExA(key, "0\\win32", 0, NULL, 0, KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) { if (RegSetValueExW(subKey, NULL, 0, REG_SZ, (BYTE *)szFullPath, lstrlenW(szFullPath) * sizeof(OLECHAR)) != ERROR_SUCCESS) res = E_FAIL; RegCloseKey(subKey); } else res = E_FAIL; if (res == S_OK && RegCreateKeyExA(key, "FLAGS", 0, NULL, 0, KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) { CHAR buf[20]; /* FIXME: is %u correct? */ snprintf(buf, sizeof(buf), "%u", attr->wLibFlags); if (RegSetValueExA(subKey, NULL, 0, REG_SZ, buf, lstrlenA(buf) + 1) != ERROR_SUCCESS) res = E_FAIL; } RegCloseKey(key); } else res = E_FAIL; ITypeLib_ReleaseTLibAttr(ptlib, attr); return res; } /****************************************************************************** * 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) { TRACE("(IID: %s): stub\n",debugstr_guid(libid)); return S_OK; /* FIXME: pretend everything is OK */ } /**************************************************************************** * OaBuildVersion (TYPELIB.15) * * known TYPELIB.DLL versions: * * OLE 2.01 no OaBuildVersion() avail 1993 -- --- * OLE 2.02 1993-94 02 3002 * OLE 2.03 23 730 * OLE 2.03 03 3025 * OLE 2.03 W98 SE orig. file !! 1993-95 10 3024 * OLE 2.1 NT 1993-95 ?? ??? * OLE 2.3.1 W95 23 700 * OLE2 4.0 NT4SP6 1993-98 40 4277 */ DWORD WINAPI OaBuildVersion16(void) { /* FIXME: I'd like to return the highest currently known version value * in case the user didn't force a --winver, but I don't know how * to retrieve the "versionForced" info from misc/version.c :( * (this would be useful in other places, too) */ FIXME("Please report to a.mohr@mailto.de if you get version error messages !\n"); switch(GetVersion() & 0x8000ffff) /* mask off build number */ { case 0x80000a03: /* WIN31 */ return MAKELONG(3027, 3); /* WfW 3.11 */ case 0x80000004: /* WIN95 */ return MAKELONG(700, 23); /* Win95A */ case 0x80000a04: /* WIN98 */ return MAKELONG(3024, 10); /* W98 SE */ case 0x00000004: /* NT4 */ return MAKELONG(4277, 40); /* NT4 SP6 */ default: FIXME("Version value not known yet. Please investigate it!\n"); return 0; } } /* for better debugging info leave the static out for the time being */ #define static /*======================= ITypeLib implementation =======================*/ typedef struct tagTLBCustData { GUID guid; VARIANT data; struct tagTLBCustData* next; } TLBCustData; /* data structure for import typelibs */ typedef struct tagTLBImpLib { int offset; /* offset in the file */ GUID guid; /* libid */ BSTR name; /* name; */ LCID lcid; /* lcid of imported typelib */ WORD wVersionMajor; /* major version number */ WORD wVersionMinor; /* minor version number */ struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib */ struct tagTLBImpLib * next; } TLBImpLib; /* internal ITypeLib data */ typedef struct tagITypeLibImpl { ICOM_VFIELD(ITypeLib2); UINT ref; TLIBATTR LibAttr; /* guid,lcid,syskind,version,flags */ /* strings can be stored in tlb as multibyte strings BUT they are *always* * exported to the application as a UNICODE string. */ BSTR Name; BSTR DocString; BSTR HelpFile; BSTR HelpStringDll; unsigned long dwHelpContext; int TypeInfoCount; /* nr of typeinfo's in librarry */ struct tagITypeInfoImpl *pTypeInfo; /* linked list of type info data */ int ctCustData; /* number of items in cust data list */ TLBCustData * pCustData; /* linked list to cust data; */ TLBImpLib * pImpLibs; /* linked list to all imported typelibs */ TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the libary */ } ITypeLibImpl; static struct ICOM_VTABLE(ITypeLib2) tlbvt; /* ITypeLib methods */ static ITypeLib2* ITypeLib2_Constructor(LPVOID pLib, DWORD dwTLBLength); /*======================= ITypeInfo implementation =======================*/ /* data for refernced types in a coclass, or an inherited interface */ typedef struct tagTLBRefType { GUID guid; /* guid of the referenced type */ /* (important if its a imported type) */ HREFTYPE reference; int flags; int ctCustData; TLBCustData * pCustData;/* linked list to custom data; */ TLBImpLib *pImpTLInfo; struct tagTLBRefType * next; } TLBRefType; /* internal Parameter data */ typedef struct tagTLBParDesc { BSTR Name; int ctCustData; TLBCustData * pCustData; /* linked list to cust data; */ TLBRefType * pRefType; /* linked list to referenced types */ } TLBParDesc; /* internal Function data */ typedef struct tagTLBFuncDesc { FUNCDESC funcdesc; /* lots of info on the function and its attributes. */ BSTR Name; /* the name of this function */ TLBParDesc *pParamDesc; /* array with name and custom data */ int helpcontext; int HelpStringContext; BSTR HelpString; BSTR Entry; /* if its Hiword==0, it numeric; -1 is not present*/ int ctCustData; TLBCustData * pCustData; /* linked list to cust data; */ struct tagTLBFuncDesc * next; } TLBFuncDesc; /* internal Variable data */ typedef struct tagTLBVarDesc { VARDESC vardesc; /* lots of info on the variable and its attributes. */ BSTR Name; /* the name of this variable */ int HelpContext; int HelpStringContext; /* fixme: where? */ BSTR HelpString; int ctCustData; TLBCustData * pCustData;/* linked list to cust data; */ struct tagTLBVarDesc * next; } TLBVarDesc; /* internal TypeInfo data */ typedef struct tagITypeInfoImpl { ICOM_VFIELD(ITypeInfo2); UINT ref; TYPEATTR TypeAttr ; /* _lots_ of type information. */ ITypeLibImpl * pTypeLib; /* back pointer to typelib */ int index; /* index in this typelib; */ /* type libs seem to store the doc strings in ascii * so why should we do it in unicode? */ BSTR Name; BSTR DocString; unsigned long dwHelpContext; unsigned long dwHelpStringContext; /* functions */ TLBFuncDesc * funclist; /* linked list with function descriptions */ /* variables */ TLBVarDesc * varlist; /* linked list with variable descriptions */ /* Implemented Interfaces */ TLBRefType * impltypelist; int ctCustData; TLBCustData * pCustData; /* linked list to cust data; */ struct tagITypeInfoImpl * next; } ITypeInfoImpl; static struct ICOM_VTABLE(ITypeInfo2) tinfvt; static ITypeInfo2 * WINAPI ITypeInfo_Constructor(); typedef struct tagTLBContext { unsigned int oStart; /* start of TLB in file */ unsigned int pos; /* current pos */ unsigned int length; /* total length */ void *mapping; /* memory mapping */ TLBSegDir * pTblDir; ITypeLibImpl* pLibInfo; } TLBContext; static void TLB_DoRefType(TLBContext *pcx, int offset, TLBRefType ** pprtd); /* debug */ static void dump_VarType(VARTYPE vt,char *szVarType) { /* FIXME : we could have better trace here, depending on the VARTYPE * of the variant */ switch(vt) { case VT_UI1: sprintf(szVarType, "VT_UI"); break; case VT_I2: sprintf(szVarType, "VT_I2"); break; case VT_I4: sprintf(szVarType, "VT_I4"); break; case VT_R4: sprintf(szVarType, "VT_R4"); break; case VT_R8: sprintf(szVarType, "VT_R8"); break; case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break; case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break; case VT_CY: sprintf(szVarType, "VT_CY"); break; case VT_DATE: sprintf(szVarType, "VT_DATE"); break; case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break; case VT_BYREF: case VT_UNKNOWN: sprintf(szVarType, "VT_BYREF"); break; case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break; case VT_ARRAY: sprintf(szVarType, "VT_ARRAY"); break; case VT_I1: sprintf(szVarType, "VT_I2"); break; case VT_UI2: sprintf(szVarType, "VT_UI2"); break; case VT_UI4: sprintf(szVarType, "VT_UI4"); break; case VT_INT: sprintf(szVarType, "VT_INT"); break; case VT_UINT: sprintf(szVarType, "VT_UINT"); break; default: sprintf(szVarType, "unknown");break; } } static void dump_ELEMDESC(ELEMDESC *edesc) { char buf[200]; dump_VarType(edesc->tdesc.vt,buf); MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf); MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags); MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex); } static void dump_FUNCDESC(FUNCDESC *funcdesc) { int i; MESSAGE("memid is %d\n",(int)funcdesc->memid); for (i=0;icParams;i++) MESSAGE("Param %d:\n",i);dump_ELEMDESC(funcdesc->lprgelemdescParam+i); MESSAGE("\tfunckind: %d (",funcdesc->funckind); switch (funcdesc->funckind) { case FUNC_VIRTUAL: MESSAGE("virtual");break; case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break; case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break; case FUNC_STATIC: MESSAGE("static");break; case FUNC_DISPATCH: MESSAGE("dispatch");break; default: MESSAGE("unknown");break; } MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind); switch (funcdesc->invkind) { case INVOKE_FUNC: MESSAGE("func");break; case INVOKE_PROPERTYGET: MESSAGE("property get");break; case INVOKE_PROPERTYPUT: MESSAGE("property put");break; case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break; } MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv); switch (funcdesc->callconv) { case CC_CDECL: MESSAGE("cdecl");break; case CC_PASCAL: MESSAGE("pascal");break; case CC_STDCALL: MESSAGE("stdcall");break; case CC_SYSCALL: MESSAGE("syscall");break; default:break; } MESSAGE(")\n\toVft: %d\n", funcdesc->oVft); MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt); MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags); } static void dump_TLBFuncDescOne(TLBFuncDesc * pfd) { int i; if (!TRACE_ON(typelib)) return; MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams); for (i=0;ifuncdesc.cParams;i++) MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name)); dump_FUNCDESC(&(pfd->funcdesc)); MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString)); MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry)); } static void dump_TLBFuncDesc(TLBFuncDesc * pfd) { while (pfd) { dump_TLBFuncDescOne(pfd); pfd = pfd->next; }; } static void dump_TLBVarDesc(TLBVarDesc * pvd) { while (pvd) { TRACE_(typelib)("%s\n", debugstr_w(pvd->Name)); pvd = pvd->next; }; } static void dump_TLBRefType(TLBRefType * prt) { while (prt) { TRACE_(typelib)("%s\n", debugstr_guid(&(prt->guid))); TRACE_(typelib)(" href:0x%08lx\n", prt->reference); prt = prt->next; }; } static void dump_Variant(VARIANT * pvar) { char szVarType[15]; TRACE("(%p)\n", pvar); if (!pvar) return; ZeroMemory(szVarType, sizeof(szVarType)); /* FIXME : we could have better trace here, depending on the VARTYPE * of the variant */ dump_VarType(V_VT(pvar),szVarType); TRACE("VARTYPE: %s\n", szVarType); switch (V_VT(pvar)) { case VT_R4: TRACE("%3.3e\n", V_UNION(pvar, fltVal)); break; case VT_R8: TRACE("%3.3e\n", V_UNION(pvar, dblVal)); break; default: TRACE("%ld\n", V_UNION(pvar, lVal)); break; } if (pvar->vt & VT_BYREF) return dump_Variant(pvar->u.pvarVal); } static void dump_DispParms(DISPPARAMS * pdp) { int index = 0; TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs); while (index < pdp->cArgs) { dump_Variant( &pdp->rgvarg[index] ); ++index; } } static char * typekind_desc[] = { "TKIND_ENUM", "TKIND_RECORD", "TKIND_MODULE", "TKIND_INTERFACE", "TKIND_DISPATCH", "TKIND_COCLASS", "TKIND_ALIAS", "TKIND_UNION", "TKIND_MAX" }; static void dump_TypeInfo(ITypeInfoImpl * pty) { TRACE("%p ref=%u\n", pty, pty->ref); TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid))); TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]); TRACE("fct:%u var:%u impl:%u\n", pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes); TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index); TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString)); dump_TLBFuncDesc(pty->funclist); dump_TLBVarDesc(pty->varlist); dump_TLBRefType(pty->impltypelist); } 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() { DebugBreak(); } static void * TLB_Alloc(unsigned size) { void * ret; if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){ /* FIXME */ ERR("cannot allocate memory\n"); } return ret; } static void TLB_Free(void * ptr) { HeapFree(GetProcessHeap(), 0, ptr); } /* read function */ DWORD TLB_Read(void *buffer, DWORD count, TLBContext *pcx, long where ) { TRACE_(typelib)("pos=0x%08x len=0x%08lx 0x%08x 0x%08x 0x%08lx\n", pcx->pos, count, pcx->oStart, pcx->length, where); if (where != DO_NOT_SEEK) { where += pcx->oStart; if (where > pcx->length) { /* FIXME */ ERR("seek beyond end (%ld/%d)\n", where, pcx->length ); TLB_abort(); } pcx->pos = where; } if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos; memcpy( buffer, (char *)pcx->mapping + pcx->pos, count ); pcx->pos += count; return count; } static void TLB_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx) { TRACE_(typelib)("%s\n", debugstr_guid(pGuid)); 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 ); } BSTR TLB_ReadName( TLBContext *pcx, int offset) { char * name; TLBNameIntro niName; int lengthInChars; WCHAR* pwstring = NULL; BSTR bstrName = NULL; 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'; lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, name, -1, NULL, 0); /* no invalid characters in string */ if (lengthInChars) { pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars); /* don't check for invalid character since this has been done previously */ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, pwstring, lengthInChars); bstrName = SysAllocStringLen(pwstring, lengthInChars); lengthInChars = SysStringLen(bstrName); HeapFree(GetProcessHeap(), 0, pwstring); } TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars); return bstrName; } BSTR TLB_ReadString( TLBContext *pcx, int offset) { char * string; INT16 length; int lengthInChars; BSTR bstr = NULL; 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'; lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, string, -1, NULL, 0); /* no invalid characters in string */ if (lengthInChars) { WCHAR* pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars); /* don't check for invalid character since this has been done previously */ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, pwstring, lengthInChars); bstr = SysAllocStringLen(pwstring, lengthInChars); lengthInChars = SysStringLen(bstr); HeapFree(GetProcessHeap(), 0, pwstring); } TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars); return bstr; } /* * read a value and fill a VARIANT structure */ static void TLB_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx ) { int size; TRACE_(typelib)("\n"); 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 ); TRACE_(typelib)("Vartype = %x\n", pVar->vt); 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 ); if(size <= 0) { FIXME("BSTR length = %d?\n", size); } else { 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("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; TRACE_(typelib)("\n"); 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))]; TRACE_(typelib)("vt type = %X\n", pTd->vt); } 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, i; int recoffset = offset + sizeof(INT); char recbuf[512]; TLBFuncRecord * pFuncRec=(TLBFuncRecord *) recbuf; TRACE_(typelib)("\n"); 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 = (WCHAR*) 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) { int j = 0; TLBParameterInfo paraminfo; (*pptfd)->funcdesc.lprgelemdescParam = TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC)); (*pptfd)->pParamDesc = TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc)); TLB_Read(¶minfo, sizeof(paraminfo), pcx, recoffset + reclength - pFuncRec->nrargs * sizeof(TLBParameterInfo)); for ( j = 0 ; j < pFuncRec->nrargs ; j++ ) { TYPEDESC* lpArgTypeDesc = 0; 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; /* SEEK value = jump to offset, * from there jump to the end of record, * go back by (j-1) arguments */ TLB_Read( ¶minfo , sizeof(TLBParameterInfo), pcx, recoffset + reclength - ((pFuncRec->nrargs - j - 1) * sizeof(TLBParameterInfo))); lpArgTypeDesc = & ((*pptfd)->funcdesc.lprgelemdescParam[j].tdesc); while ( lpArgTypeDesc != NULL ) { switch ( lpArgTypeDesc->vt ) { case VT_PTR: lpArgTypeDesc = lpArgTypeDesc->u.lptdesc; break; case VT_CARRAY: lpArgTypeDesc = & (lpArgTypeDesc->u.lpadesc->tdescElem); break; case VT_USERDEFINED: (*pptfd)->pParamDesc[j].pRefType = TLB_Alloc(sizeof(TLBRefType)); TLB_DoRefType(pcx, lpArgTypeDesc->u.hreftype, & ( (*pptfd)->pParamDesc[j].pRefType )); lpArgTypeDesc = NULL; break; default: lpArgTypeDesc = NULL; } } } /* parameter is the return value! */ if ( paraminfo.Flags & PARAMFLAG_FRETVAL ) { TYPEDESC* lpArgTypeDesc; (*pptfd)->funcdesc.elemdescFunc = (*pptfd)->funcdesc.lprgelemdescParam[j]; lpArgTypeDesc = & ((*pptfd)->funcdesc.elemdescFunc.tdesc) ; while ( lpArgTypeDesc != NULL ) { switch ( lpArgTypeDesc->vt ) { case VT_PTR: lpArgTypeDesc = lpArgTypeDesc->u.lptdesc; break; case VT_CARRAY: lpArgTypeDesc = & (lpArgTypeDesc->u.lpadesc->tdescElem); break; case VT_USERDEFINED: (*pptfd)->pParamDesc[j].pRefType = TLB_Alloc(sizeof(TLBRefType)); TLB_DoRefType(pcx, lpArgTypeDesc->u.hreftype, &((*pptfd)->pParamDesc[j].pRefType)); lpArgTypeDesc = NULL; break; default: lpArgTypeDesc = NULL; } } } /* second time around */ for(j=0;jnrargs;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; TRACE_(typelib)("\n"); 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;iName=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 from import, its an offset+1 in the ImpInfo table * */ static void TLB_DoRefType(TLBContext *pcx, int offset, TLBRefType ** pprtd) { int j; TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset); if(!HREFTYPE_INTHISFILE( offset)) { /* external typelib */ TLBImpInfo impinfo; TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs); TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc)); 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("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; TRACE_(typelib)("\n"); for(i=0;ipTblDir->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 */ ITypeInfoImpl * TLB_DoTypeInfo( TLBContext *pcx, int count, ITypeLibImpl * pLibInfo) { TLBTypeInfoBase tiBase; ITypeInfoImpl *ptiRet; TRACE_(typelib)("count=%u\n", count); ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor(); TLB_Read(&tiBase, sizeof(tiBase) ,pcx , pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase)); /* this is where we are coming from */ ptiRet->pTypeLib = pLibInfo; ptiRet->index=count; /* fill in the typeattr fields */ FIXME("Assign constructor/destructor memid\n"); 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", debugstr_w(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 ){ switch(ptiRet->TypeAttr.typekind) { case TKIND_COCLASS: TLB_DoImplTypes(pcx, ptiRet->TypeAttr.cImplTypes , tiBase.datatype1, & ptiRet->impltypelist); break; case TKIND_DISPATCH: ptiRet->impltypelist=TLB_Alloc(sizeof(TLBRefType)); if (tiBase.datatype1 != -1) { TLB_DoRefType(pcx, tiBase.datatype1, & ptiRet->impltypelist); } else { char* szStdOle = "stdole2.tlb\0"; int nStdOleLen = strlen(szStdOle); ptiRet->impltypelist->guid = IID_IDispatch; ptiRet->impltypelist->reference = -1; ptiRet->impltypelist->pImpTLInfo = TLB_Alloc(sizeof(TLBImpLib)); ptiRet->impltypelist->pImpTLInfo->guid = IID_StdOle; ptiRet->impltypelist->pImpTLInfo->name = SysAllocStringLen(NULL, nStdOleLen + 1); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szStdOle, -1, ptiRet->impltypelist->pImpTLInfo->name, SysStringLen(ptiRet->impltypelist->pImpTLInfo->name)); ptiRet->impltypelist->pImpTLInfo->lcid = 0; ptiRet->impltypelist->pImpTLInfo->wVersionMajor = 2; ptiRet->impltypelist->pImpTLInfo->wVersionMinor = 0; } break; default: ptiRet->impltypelist=TLB_Alloc(sizeof(TLBRefType)); TLB_DoRefType(pcx, tiBase.datatype1, & ptiRet->impltypelist); break; } } ptiRet->ctCustData= TLB_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData); TRACE_(typelib)("%s guid: %s kind:%s\n", debugstr_w(ptiRet->Name), debugstr_guid(&ptiRet->TypeAttr.guid), typekind_desc[ptiRet->TypeAttr.typekind]); return ptiRet; } /**************************************************************************** * TLB_ReadTypeLib * * find the type of the typelib file and map the typelib resource into * the memory */ #define MSFT_SIGNATURE 0x5446534D /* "MSFT" */ int TLB_ReadTypeLib(LPSTR pszFileName, ITypeLib2 **ppTypeLib) { int ret = E_FAIL; DWORD dwSignature = 0; HFILE hFile; int nStrLen = strlen(pszFileName); int i; PCHAR pszTypeLibIndex = NULL; PCHAR pszDllName = NULL; TRACE_(typelib)("%s\n", pszFileName); *ppTypeLib = NULL; /* is it a DLL? */ for (i=0 ; i < nStrLen ; ++i) { pszFileName[i] = tolower(pszFileName[i]); } pszTypeLibIndex = strstr(pszFileName, ".dll"); /* find if there's a back-slash after .DLL (good sign of the presence of a typelib index) */ if (pszTypeLibIndex) { pszTypeLibIndex = strstr(pszTypeLibIndex, "\\"); } /* is there any thing after trailing back-slash ? */ if (pszTypeLibIndex && pszTypeLibIndex < pszFileName + nStrLen) { /* yes -> it's a index! store DLL name, without the trailing back-slash */ size_t nMemToAlloc = pszTypeLibIndex - pszFileName; pszDllName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nMemToAlloc + 1); strncpy(pszDllName, pszFileName, nMemToAlloc); /* move index string pointer pass the backslash */ while (*pszTypeLibIndex == '\\') ++pszTypeLibIndex; } else { /* No index, reset variable to 1 */ pszDllName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nStrLen + 1); strncpy(pszDllName, pszFileName, nStrLen); pszTypeLibIndex = "1\0"; } TRACE_(typelib)("File name without index %s\n", pszDllName); TRACE_(typelib)("Index of typelib %s\n", pszTypeLibIndex); /* check the signature of the file */ hFile = CreateFileA( pszDllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); if (INVALID_HANDLE_VALUE != hFile) { HANDLE hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL ); if (hMapping) { LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); if(pBase) { /* first try to load as *.tlb */ dwSignature = *((DWORD*) pBase); if ( dwSignature == MSFT_SIGNATURE) { /* retrieve file size */ DWORD dwTLBLength = GetFileSize(hFile, NULL); *ppTypeLib = ITypeLib2_Constructor(pBase, dwTLBLength); ITypeLib2_AddRef(*ppTypeLib); } UnmapViewOfFile(pBase); } CloseHandle(hMapping); } CloseHandle(hFile); } if( (WORD)dwSignature == IMAGE_DOS_SIGNATURE ) { /* find the typelibrary resource*/ HINSTANCE hinstDLL = LoadLibraryExA(pszDllName, 0, DONT_RESOLVE_DLL_REFERENCES| LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH); if (hinstDLL) { HRSRC hrsrc = FindResourceA(hinstDLL, MAKEINTRESOURCEA(atoi(pszTypeLibIndex)), "TYPELIB"); if (hrsrc) { HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc); if (hGlobal) { LPVOID pBase = LockResource(hGlobal); DWORD dwTLBLength = SizeofResource(hinstDLL, hrsrc); if (pBase) { /* try to load as incore resource */ dwSignature = *((DWORD*) pBase); if ( dwSignature == MSFT_SIGNATURE) { *ppTypeLib = ITypeLib2_Constructor(pBase, dwTLBLength); ITypeLib2_AddRef(*ppTypeLib); } else { FIXME("Header type magic 0x%08lx not supported.\n",dwSignature); } } FreeResource( hGlobal ); } } FreeLibrary(hinstDLL); } } HeapFree(GetProcessHeap(), 0, pszDllName); if(*ppTypeLib) ret = S_OK; else ERR("Loading of typelib %s failed with error 0x%08lx\n", pszFileName, GetLastError()); return ret; } /*================== ITypeLib(2) Methods ===================================*/ /**************************************************************************** * ITypeLib2_Constructor * * loading a typelib from a in-memory image */ static ITypeLib2* ITypeLib2_Constructor(LPVOID pLib, DWORD dwTLBLength) { TLBContext cx; long lPSegDir; TLB2Header tlbHeader; TLBSegDir tlbSegDir; ITypeLibImpl * pTypeLibImpl; TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength); pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl)); if (!pTypeLibImpl) return NULL; ICOM_VTBL(pTypeLibImpl) = &tlbvt; pTypeLibImpl->ref = 1; /* get pointer to beginning of typelib data */ cx.pos = 0; cx.oStart=0; cx.mapping = pLib; cx.pLibInfo = pTypeLibImpl; cx.length = dwTLBLength; /* read header */ TLB_Read((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0); TRACE("header:\n"); TRACE("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 ); if (memcmp(&tlbHeader.magic1,TLBMAGIC2,4)) { FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1); return NULL; } /* 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 */ TRACE("read segment directory (at %ld)\n",lPSegDir); 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("cannot find the table directory, ptr=0x%lx\n",lPSegDir); HeapFree(GetProcessHeap(),0,pTypeLibImpl); return NULL; } /* now fill our internal data */ /* TLIBATTR fields */ TLB_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx); pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid; pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */ pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version); pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version); pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */ /* name, eventually add to a hash table */ pTypeLibImpl->Name = TLB_ReadName(&cx, tlbHeader.NameOffset); /* help info */ pTypeLibImpl->DocString = TLB_ReadString(&cx, tlbHeader.helpstring); pTypeLibImpl->HelpFile = TLB_ReadString(&cx, tlbHeader.helpfile); if( tlbHeader.varflags & HELPDLLFLAG) { int offset; TLB_Read(&offset, sizeof(offset), &cx, sizeof(tlbHeader)); pTypeLibImpl->HelpStringDll = TLB_ReadString(&cx, offset); } pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext; /* custom data */ if(tlbHeader.CustomDataOffset >= 0) { pTypeLibImpl->ctCustData = TLB_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData); } /* fill in typedescriptions */ if(tlbSegDir.pTypdescTab.length > 0) { int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT)); INT16 td[4]; pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC)); TLB_Read(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset); for(i=0; ipTypeDesc[i].vt = td[0] & VT_TYPEMASK; if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY) { /* FIXME: check safearray */ if(td[3] < 0) V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lptdesc)= & stndTypeDesc[td[2]]; else V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lptdesc)= & pTypeLibImpl->pTypeDesc[td[2]/8]; } else if(td[0] == VT_CARRAY) { /* array descr table here */ V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc) = (void *)((int) td[2]); /* temp store offset in*/ } else if(td[0] == VT_USERDEFINED) { V_UNION(&(pTypeLibImpl->pTypeDesc[i]),hreftype) = MAKELONG(td[2],td[3]); } if(++ipTypeDesc[i].vt != VT_CARRAY) continue; if(tlbSegDir.pArrayDescriptions.offset>0) { TLB_Read(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)); V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc) = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1)); if(td[1]<0) V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->tdescElem.vt = td[0] & VT_TYPEMASK; else V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->tdescElem = stndTypeDesc[td[0]/8]; V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->cDims = td[2]; for(j = 0; jpTypeDesc[i]),lpadesc)->rgbounds[j].cElements, sizeof(INT), &cx, DO_NOT_SEEK); TLB_Read(& V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc)->rgbounds[j].lLbound, sizeof(INT), &cx, DO_NOT_SEEK); } } else { V_UNION(&(pTypeLibImpl->pTypeDesc[i]),lpadesc) = NULL; ERR("didn't find array description data\n"); } } } /* imported type libs */ if(tlbSegDir.pImpFiles.offset>0) { TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs); int oGuid, offset = tlbSegDir.pImpFiles.offset; 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_Read(&(*ppImpLib)->lcid, sizeof(LCID), &cx, DO_NOT_SEEK); TLB_Read(&(*ppImpLib)->wVersionMajor, sizeof(WORD), &cx, DO_NOT_SEEK); TLB_Read(&(*ppImpLib)->wVersionMinor, sizeof(WORD), &cx, DO_NOT_SEEK); TLB_Read(& size, sizeof(UINT16), &cx, DO_NOT_SEEK); size >>= 2; (*ppImpLib)->name = TLB_Alloc(size+1); TLB_Read((*ppImpLib)->name, size, &cx, DO_NOT_SEEK); TLB_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx); offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & 0xfffffffc; ppImpLib = &(*ppImpLib)->next; } } /* type info's */ if(tlbHeader.nrtypeinfos >= 0 ) { /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */ ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo); int i; for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++) { *ppTI = TLB_DoTypeInfo(&cx, i, pTypeLibImpl); ITypeInfo_AddRef((ITypeInfo*) *ppTI); ppTI = &((*ppTI)->next); (pTypeLibImpl->TypeInfoCount)++; } } TRACE("(%p)\n", pTypeLibImpl); return (ITypeLib2*) pTypeLibImpl; } /* ITypeLib::QueryInterface */ static HRESULT WINAPI ITypeLib2_fnQueryInterface( ITypeLib2 * iface, REFIID riid, VOID **ppvObject) { ICOM_THIS( ITypeLibImpl, iface); TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); *ppvObject=NULL; if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid,&IID_ITypeLib)|| IsEqualIID(riid,&IID_ITypeLib2)) { *ppvObject = This; } if(*ppvObject) { ITypeLib2_AddRef(iface); TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); return S_OK; } TRACE("-- Interface: E_NOINTERFACE\n"); return E_NOINTERFACE; } /* ITypeLib::AddRef */ static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface) { ICOM_THIS( ITypeLibImpl, iface); TRACE("(%p)->ref is %u\n",This, This->ref); return ++(This->ref); } /* ITypeLib::Release */ static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) { ICOM_THIS( ITypeLibImpl, iface); --(This->ref); TRACE("(%p)->(%u)\n",This, This->ref); if (!This->ref) { /* fixme destroy child objects */ TRACE(" destroying ITypeLib(%p)\n",This); if (This->Name) { SysFreeString(This->Name); This->Name = NULL; } if (This->DocString) { SysFreeString(This->DocString); This->DocString = NULL; } if (This->HelpFile) { SysFreeString(This->HelpFile); This->HelpFile = NULL; } if (This->HelpStringDll) { SysFreeString(This->HelpStringDll); This->HelpStringDll = NULL; } ITypeInfo_Release((ITypeInfo*) This->pTypeInfo); HeapFree(GetProcessHeap(),0,This); return 0; } return This->ref; } /* ITypeLib::GetTypeInfoCount * * Returns the number of type descriptions in the type library */ static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface) { ICOM_THIS( ITypeLibImpl, iface); TRACE("(%p)->count is %d\n",This, This->TypeInfoCount); return This->TypeInfoCount; } /* ITypeLib::GetTypeInfo * * retrieves the specified type description in the library. */ static HRESULT WINAPI ITypeLib2_fnGetTypeInfo( ITypeLib2 *iface, UINT index, ITypeInfo **ppTInfo) { int i; ICOM_THIS( ITypeLibImpl, iface); ITypeInfoImpl *pTypeInfo = This->pTypeInfo; TRACE("(%p)->(index=%d) \n", This, index); if (!ppTInfo) return E_INVALIDARG; /* search element n in list */ for(i=0; i < index; i++) { pTypeInfo = pTypeInfo->next; if (!pTypeInfo) { TRACE("-- element not found\n"); return TYPE_E_ELEMENTNOTFOUND; } } *ppTInfo = (ITypeInfo *) pTypeInfo; ITypeInfo_AddRef(*ppTInfo); TRACE("-- found (%p)\n",*ppTInfo); return S_OK; } /* ITypeLibs::GetTypeInfoType * * Retrieves the type of a type description. */ static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType( ITypeLib2 *iface, UINT index, TYPEKIND *pTKind) { ICOM_THIS( ITypeLibImpl, iface); int i; ITypeInfoImpl *pTInfo = This->pTypeInfo; TRACE("(%p) index %d \n",This, index); if(!pTKind) return E_INVALIDARG; /* search element n in list */ for(i=0; i < index; i++) { if(!pTInfo) { TRACE("-- element not found\n"); return TYPE_E_ELEMENTNOTFOUND; } pTInfo = pTInfo->next; } *pTKind = pTInfo->TypeAttr.typekind; TRACE("-- found Type (%d)\n", *pTKind); return S_OK; } /* ITypeLib::GetTypeInfoOfGuid * * Retrieves the type description that corresponds to the specified GUID. * */ static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid( ITypeLib2 *iface, REFGUID guid, ITypeInfo **ppTInfo) { ICOM_THIS( ITypeLibImpl, iface); ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */ TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid)); if (!pTypeInfo) return TYPE_E_ELEMENTNOTFOUND; /* search linked list for guid */ while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) ) { pTypeInfo = pTypeInfo->next; if (!pTypeInfo) { /* end of list reached */ TRACE("-- element not found\n"); return TYPE_E_ELEMENTNOTFOUND; } } TRACE("-- found (%p, %s)\n", pTypeInfo, debugstr_w(pTypeInfo->Name)); *ppTInfo = (ITypeInfo*)pTypeInfo; ITypeInfo_AddRef(*ppTInfo); return S_OK; } /* ITypeLib::GetLibAttr * * Retrieves the structure that contains the library's attributes. * */ static HRESULT WINAPI ITypeLib2_fnGetLibAttr( ITypeLib2 *iface, LPTLIBATTR *ppTLibAttr) { ICOM_THIS( ITypeLibImpl, iface); TRACE("(%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 ITypeLib2_fnGetTypeComp( ITypeLib2 *iface, ITypeComp **ppTComp) { ICOM_THIS( ITypeLibImpl, iface); FIXME("(%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 ITypeLib2_fnGetDocumentation( ITypeLib2 *iface, INT index, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) { ICOM_THIS( ITypeLibImpl, iface); HRESULT result = E_INVALIDARG; ITypeInfo *pTInfo; TRACE("(%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 && This->Name) { *pBstrName = SysAllocString(This->Name); if (!(*pBstrName)) return STG_E_INSUFFICIENTMEMORY; } if(pBstrDocString && This->DocString) { *pBstrDocString = SysAllocString(This->DocString); if (!(*pBstrDocString)) return STG_E_INSUFFICIENTMEMORY; } if(pdwHelpContext) { *pdwHelpContext = This->dwHelpContext; } if(pBstrHelpFile && This->HelpFile) { *pBstrHelpFile = SysAllocString(This->HelpFile); if (!(*pBstrHelpFile)) return STG_E_INSUFFICIENTMEMORY; } result = S_OK; } else { /* for a typeinfo */ result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo); if(SUCCEEDED(result)) { result = ITypeInfo_GetDocumentation(pTInfo, MEMBERID_NIL, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); ITypeInfo_Release(pTInfo); } } return result; } /* ITypeLib::IsName * * Indicates whether a passed-in string contains the name of a type or member * described in the library. * */ static HRESULT WINAPI ITypeLib2_fnIsName( ITypeLib2 *iface, LPOLESTR szNameBuf, ULONG lHashVal, BOOL *pfName) { ICOM_THIS( ITypeLibImpl, iface); ITypeInfoImpl *pTInfo; TLBFuncDesc *pFInfo; TLBVarDesc *pVInfo; int i; UINT nNameBufLen = SysStringLen(szNameBuf); TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal, pfName); *pfName=TRUE; for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){ if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) { if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; for(i=0;ifuncdesc.cParams;i++) if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; } for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; } *pfName=FALSE; ITypeLib2_fnIsName_exit: TRACE("(%p)slow! search for %s: %s found!\n", This, debugstr_w(szNameBuf), *pfName?"NOT":""); 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 ITypeLib2_fnFindName( ITypeLib2 *iface, LPOLESTR szNameBuf, ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *rgMemId, UINT16 *pcFound) { ICOM_THIS( ITypeLibImpl, iface); ITypeInfoImpl *pTInfo; TLBFuncDesc *pFInfo; TLBVarDesc *pVInfo; int i,j = 0; UINT nNameBufLen = SysStringLen(szNameBuf); for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){ if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit; for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) { if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit; for(i=0;ifuncdesc.cParams;i++) if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit; } for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit; continue; ITypeLib2_fnFindName_exit: ITypeInfo_AddRef((ITypeInfo*)pTInfo); ppTInfo[j]=(LPTYPEINFO)pTInfo; j++; } TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n", This, *pcFound, debugstr_w(szNameBuf), j); *pcFound=j; return S_OK; } /* ITypeLib::ReleaseTLibAttr * * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr. * */ static VOID WINAPI ITypeLib2_fnReleaseTLibAttr( ITypeLib2 *iface, TLIBATTR *pTLibAttr) { ICOM_THIS( ITypeLibImpl, iface); TRACE("freeing (%p)\n",This); /* nothing to do */ } /* ITypeLib2::GetCustData * * gets the custom data */ static HRESULT WINAPI ITypeLib2_fnGetCustData( ITypeLib2 * iface, REFGUID guid, VARIANT *pVarVal) { ICOM_THIS( ITypeLibImpl, iface); TLBCustData *pCData; for(pCData=This->pCustData; pCData; pCData = pCData->next) { if( IsEqualIID(guid, &pCData->guid)) break; } TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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( ITypeLib2 * iface, ULONG *pcUniqueNames, ULONG *pcchUniqueNames) { ICOM_THIS( ITypeLibImpl, iface); FIXME("(%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( ITypeLib2 * iface, INT index, LCID lcid, BSTR *pbstrHelpString, DWORD *pdwHelpStringContext, BSTR *pbstrHelpStringDll) { ICOM_THIS( ITypeLibImpl, iface); HRESULT result; ITypeInfo *pTInfo; FIXME("(%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=SysAllocString(This->DocString); if(pdwHelpStringContext) *pdwHelpStringContext=This->dwHelpContext; if(pbstrHelpStringDll) *pbstrHelpStringDll=SysAllocString(This->HelpStringDll); result = S_OK; } else { /* for a typeinfo */ result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo); if(SUCCEEDED(result)) { ITypeInfo2 * pTInfo2; result = ITypeInfo_QueryInterface(pTInfo, &IID_ITypeInfo2, (LPVOID*) &pTInfo2); if(SUCCEEDED(result)) { result = ITypeInfo2_GetDocumentation2(pTInfo2, MEMBERID_NIL, lcid, pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll); ITypeInfo2_Release(pTInfo2); } ITypeInfo_Release(pTInfo); } } return result; } /* ITypeLib2::GetAllCustData * * Gets all custom data items for the library. * */ static HRESULT WINAPI ITypeLib2_fnGetAllCustData( ITypeLib2 * iface, CUSTDATA *pCustData) { ICOM_THIS( ITypeLibImpl, iface); TLBCustData *pCData; int i; TRACE("(%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(" OUT OF MEMORY! \n"); return E_OUTOFMEMORY; } return S_OK; } static ICOM_VTABLE(ITypeLib2) tlbvt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE ITypeLib2_fnQueryInterface, ITypeLib2_fnAddRef, ITypeLib2_fnRelease, ITypeLib2_fnGetTypeInfoCount, ITypeLib2_fnGetTypeInfo, ITypeLib2_fnGetTypeInfoType, ITypeLib2_fnGetTypeInfoOfGuid, ITypeLib2_fnGetLibAttr, ITypeLib2_fnGetTypeComp, ITypeLib2_fnGetDocumentation, ITypeLib2_fnIsName, ITypeLib2_fnFindName, ITypeLib2_fnReleaseTLibAttr, ITypeLib2_fnGetCustData, ITypeLib2_fnGetLibStatistics, ITypeLib2_fnGetDocumentation2, ITypeLib2_fnGetAllCustData }; /*================== ITypeInfo(2) Methods ===================================*/ static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void) { ITypeInfoImpl * pTypeInfoImpl; pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl)); if (pTypeInfoImpl) { ICOM_VTBL(pTypeInfoImpl) = &tinfvt; pTypeInfoImpl->ref=1; } TRACE("(%p)\n", pTypeInfoImpl); return (ITypeInfo2*) pTypeInfoImpl; } /* ITypeInfo::QueryInterface */ static HRESULT WINAPI ITypeInfo_fnQueryInterface( ITypeInfo2 *iface, REFIID riid, VOID **ppvObject) { ICOM_THIS( ITypeLibImpl, iface); TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); *ppvObject=NULL; if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid,&IID_ITypeInfo)|| IsEqualIID(riid,&IID_ITypeInfo2)) *ppvObject = This; if(*ppvObject){ ITypeInfo_AddRef(iface); TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); return S_OK; } TRACE("-- Interface: E_NOINTERFACE\n"); return E_NOINTERFACE; } /* ITypeInfo::AddRef */ static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface) { ICOM_THIS( ITypeInfoImpl, iface); ++(This->ref); TRACE("(%p)->ref is %u\n",This, This->ref); return This->ref; } /* ITypeInfo::Release */ static ULONG WINAPI ITypeInfo_fnRelease( ITypeInfo2 *iface) { ICOM_THIS( ITypeInfoImpl, iface); --(This->ref); TRACE("(%p)->(%u)\n",This, This->ref); if (!This->ref) { FIXME("destroy child objects\n"); TRACE("destroying ITypeInfo(%p)\n",This); if (This->Name) { SysFreeString(This->Name); This->Name = 0; } if (This->DocString) { SysFreeString(This->DocString); This->DocString = 0; } if (This->next) { ITypeInfo_Release((ITypeInfo*)This->next); } HeapFree(GetProcessHeap(),0,This); return 0; } return This->ref; } /* ITypeInfo::GetTypeAttr * * Retrieves a TYPEATTR structure that contains the attributes of the type * description. * */ static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface, LPTYPEATTR *ppTypeAttr) { ICOM_THIS( ITypeInfoImpl, iface); TRACE("(%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( ITypeInfo2 *iface, ITypeComp * *ppTComp) { ICOM_THIS( ITypeInfoImpl, iface); FIXME("(%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( ITypeInfo2 *iface, UINT index, LPFUNCDESC *ppFuncDesc) { ICOM_THIS( ITypeInfoImpl, iface); int i; TLBFuncDesc * pFDesc; TRACE("(%p) index %d\n", This, index); for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next) ; if(pFDesc){ /* FIXME: must do a copy here */ *ppFuncDesc=&pFDesc->funcdesc; return S_OK; } return E_INVALIDARG; } /* ITypeInfo::GetVarDesc * * Retrieves a VARDESC structure that describes the specified variable. * */ static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index, LPVARDESC *ppVarDesc) { ICOM_THIS( ITypeInfoImpl, iface); int i; TLBVarDesc * pVDesc; TRACE("(%p) index %d\n", This, index); for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next) ; if(pVDesc){ /* FIXME: must do a copy here */ *ppVarDesc=&pVDesc->vardesc; return S_OK; } 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( ITypeInfo2 *iface, MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) { ICOM_THIS( ITypeInfoImpl, iface); TLBFuncDesc * pFDesc; TLBVarDesc * pVDesc; int i; TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames); for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next); if(pFDesc) { /* function found, now return function and parameter names */ for(i=0; ifuncdesc.cParams; i++) { if(!i) *rgBstrNames=SysAllocString(pFDesc->Name); else rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name); } *pcNames=i; } else { for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next); if(pVDesc) { *rgBstrNames=SysAllocString(pVDesc->Name); *pcNames=1; } else { if(This->TypeAttr.typekind==TKIND_INTERFACE && This->TypeAttr.cImplTypes ) { /* recursive search */ ITypeInfo *pTInfo; HRESULT result; result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->reference, &pTInfo); if(SUCCEEDED(result)) { result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames); ITypeInfo_Release(pTInfo); return result; } WARN("Could not search inherited interface!\n"); } else { WARN("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( ITypeInfo2 *iface, UINT index, HREFTYPE *pRefType) { ICOM_THIS( ITypeInfoImpl, iface); int(i); TLBRefType *pIref = This->impltypelist; TRACE("(%p) index %d\n", This, index); dump_TypeInfo(This); if(index==(UINT)-1) { /* only valid on dual interfaces; retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH */ if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG; if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE && This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL ) { *pRefType = -1; } else { if (!pIref) return TYPE_E_ELEMENTNOTFOUND; *pRefType = pIref->reference; } } else { /* get element n from linked list */ for(i=0; pIref && inext; } if (!pIref) return TYPE_E_ELEMENTNOTFOUND; *pRefType = pIref->reference; TRACE("-- 0x%08lx %s\n",pIref->reference, debugstr_guid(&pIref->guid) ); } return S_OK; } /* ITypeInfo::GetImplTypeFlags * * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface * or base interface in a type description. */ static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface, UINT index, INT *pImplTypeFlags) { ICOM_THIS( ITypeInfoImpl, iface); int(i); TLBRefType *pIref; TRACE("(%p) index %d\n", This, index); for(i=0, pIref=This->impltypelist; inext) ; 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( ITypeInfo2 *iface, LPOLESTR *rgszNames, UINT cNames, MEMBERID *pMemId) { ICOM_THIS( ITypeInfoImpl, iface); TLBFuncDesc * pFDesc; TLBVarDesc * pVDesc; HRESULT ret=S_OK; UINT nNameLen = SysStringLen(*rgszNames); TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames), cNames); for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) { int i, j; if( !memcmp(*rgszNames, pFDesc->Name, nNameLen)) { if(cNames) *pMemId=pFDesc->funcdesc.memid; for(i=1; i < cNames; i++){ UINT nParamLen = SysStringLen(rgszNames[i]); for(j=0; jfuncdesc.cParams; j++) if(memcmp(rgszNames[i],pFDesc->pParamDesc[j].Name, nParamLen)) break; if( jfuncdesc.cParams) pMemId[i]=j; else ret=DISP_E_UNKNOWNNAME; }; return ret; } } for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) { if( !memcmp(*rgszNames, pVDesc->Name, nNameLen)) { if(cNames) *pMemId=pVDesc->vardesc.memid; 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=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->reference, &pTInfo); if(SUCCEEDED(ret)){ ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId ); ITypeInfo_Release(pTInfo); return ret; } WARN("Could not search inherited interface!\n"); } else WARN("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 DWORD _invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args) { DWORD res; if (TRACE_ON(ole)) { int i; MESSAGE("Calling %p(",func); for (i=0;ifunclist; pFDesc; pFDesc=pFDesc->next) if (pFDesc->funcdesc.memid == memid) { if (pFDesc->funcdesc.invkind & (dwFlags & ~DISPATCH_METHOD)) break; } if (pFDesc) { dump_TLBFuncDescOne(pFDesc); switch (pFDesc->funcdesc.funckind) { case FUNC_PUREVIRTUAL: case FUNC_VIRTUAL: { DWORD res; DWORD *args = (DWORD*)HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*(pFDesc->funcdesc.cParams+1)); DWORD *args2 = (DWORD*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)*(pFDesc->funcdesc.cParams)); args[0] = (DWORD)pIUnk; for (i=0;ifuncdesc.cParams;i++) { if (icArgs) { TRACE("set %d to disparg type %d vs %d\n",i, pDispParams->rgvarg[i].vt, pFDesc->funcdesc.lprgelemdescParam[i].tdesc.vt ); args[i+1] = pDispParams->rgvarg[i].u.lVal; } else { TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc); TRACE("set %d to pointer for get (type is %d)\n",i,tdesc->vt); /*FIXME: give pointers for the rest, so propertyget works*/ args[i+1] = (DWORD)&args2[i]; /* If pointer to variant, pass reference to variant * in result variant array. */ if ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_VARIANT) && pVarResult ) args[i+1] = (DWORD)(pVarResult+(i-pDispParams->cArgs)); } } if (pFDesc->funcdesc.cParamsOpt) FIXME("Does not support optional parameters (%d)\n", pFDesc->funcdesc.cParamsOpt ); res = _invoke((*(DWORD***)pIUnk)[pFDesc->funcdesc.oVft/4], pFDesc->funcdesc.callconv, pFDesc->funcdesc.cParams+1, args ); if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) { for (i=0;ifuncdesc.cParams-pDispParams->cArgs;i++) { TYPEDESC *tdesc = &(pFDesc->funcdesc.lprgelemdescParam[i].tdesc); /* If we are a pointer to a variant, we are done already */ if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT)) continue; VariantInit(&pVarResult[i]); pVarResult[i].u.intVal = args2[i]; if (tdesc->vt == VT_PTR) tdesc = tdesc->u.lptdesc; pVarResult[i].vt = tdesc->vt; /* HACK: VB5 likes this. * I do not know why. There is 1 example in MSDN which uses * this which appears broken (mixes int vals and * IDispatch*.). */ if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD)) pVarResult[i].vt = VT_DISPATCH; TRACE("storing into variant: [%d] type %d, val %08x\n", i,pVarResult[i].vt,pVarResult[i].u.intVal ); } } HeapFree(GetProcessHeap(),0,args2); HeapFree(GetProcessHeap(),0,args); return S_OK; } case FUNC_DISPATCH: { IDispatch *disp; HRESULT hr; hr = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp); if (hr) { FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n"); return hr; } FIXME("Calling Invoke in IDispatch iface. untested!\n"); hr = IDispatch_Invoke( disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams, pVarResult,pExcepInfo,pArgErr ); if (hr) FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n",hr); IDispatch_Release(disp); return hr; } default: FIXME("Unknown function invocation type %d\n",pFDesc->funcdesc.funckind); return E_FAIL; } } else { FIXME("variable based invoking not supported yet.\n"); for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) { if (pVDesc->vardesc.memid == memid) { FIXME("varseek: Found memid name %s\n",debugstr_w(((LPWSTR)pVDesc->Name))); dump_TLBVarDesc(pVDesc); break; } } } FIXME("Did not find member id %d!\n",(int)memid); return DISP_E_MEMBERNOTFOUND; } /* 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( ITypeInfo2 *iface, MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile) { ICOM_THIS( ITypeInfoImpl, iface); TLBFuncDesc * pFDesc; TLBVarDesc * pVDesc; TRACE("(%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=SysAllocString(This->Name); if(pBstrDocString) *pBstrDocString=SysAllocString(This->DocString); if(pdwHelpContext) *pdwHelpContext=This->dwHelpContext; if(pBstrHelpFile) *pBstrHelpFile=SysAllocString(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( ITypeInfo2 *iface, MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal) { ICOM_THIS( ITypeInfoImpl, iface); FIXME("(%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( ITypeInfo2 *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo) { ICOM_THIS( ITypeInfoImpl, iface); HRESULT result = E_FAIL; if(HREFTYPE_INTHISFILE(hRefType)) { ITypeLib *pTLib; int Index; result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index); if(SUCCEEDED( result )) { result=ITypeLib2_GetTypeInfo(pTLib, HREFTYPE_INDEX(hRefType), ppTInfo); ITypeLib2_Release(pTLib ); } } else if (hRefType == -1 && (((ITypeInfoImpl*) This)->TypeAttr.typekind == TKIND_DISPATCH) && (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)) { /* when we meet a DUAL dispinterface, we must create the interface * version of it. */ ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor(); /* the interface version contains the same information as the dispinterface * copy the contents of the structs. */ *pTypeInfoImpl = *This; pTypeInfoImpl->ref = 1; /* change the type to interface */ pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE; *ppTInfo = (ITypeInfo*) pTypeInfoImpl; ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl); result = S_OK; } else { /* imported type lib */ TLBRefType *pRefType = NULL; /* search in implemented types */ for( pRefType = This->impltypelist; pRefType && (pRefType->reference != hRefType); pRefType = pRefType->next); if(!pRefType) { TYPEATTR* pMyTypeAttr = &This->TypeAttr; unsigned short cFuncs = pMyTypeAttr->cFuncs; unsigned short cVars = pMyTypeAttr->cVars; /* search in arguments */ if (cFuncs > 0) { unsigned short cFuncIndex = 0; TLBFuncDesc* pCurrFunc = This->funclist; for (cFuncIndex = 0; !pRefType && cFuncIndex < cFuncs ; ++cFuncIndex) { FUNCDESC* pCurrFuncDesc = &pCurrFunc->funcdesc; short cParams = pCurrFuncDesc->cParams; short cParamIndex = 0; for (cParamIndex = 0 ; !pRefType && cParamIndex < cParams ; ++cParamIndex) { TLBParDesc* pCurrParamDesc = &(pCurrFunc->pParamDesc[cParamIndex]); if ( pCurrParamDesc->pRefType && pCurrParamDesc->pRefType->reference == hRefType) { pRefType = pCurrParamDesc->pRefType; break; /* also break from outer loop since pRefType != 0 */ } } pCurrFunc = pCurrFunc->next; } } /* search in variables */ else if (cVars > 0) { FIXME("search hreftype in variables, if any\n"); result = E_INVALIDARG; // FIXME : correct? } } /* href-referenced typeinfo found! */ if (pRefType || hRefType == -1) { ITypeLibImpl *pTypeLib = pRefType->pImpTLInfo->pImpTypeLib; if(pTypeLib) { TRACE("typeinfo in imported typelib that is already loaded\n"); result = ITypeLib2_GetTypeInfoOfGuid((LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo); } else { result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid, pRefType->pImpTLInfo->wVersionMajor, pRefType->pImpTLInfo->wVersionMinor, pRefType->pImpTLInfo->lcid, (LPTYPELIB *)&pTypeLib); if(!SUCCEEDED(result)) { BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name); TRACE("typeinfo in imported typelib that isn't already loaded\n"); result=LoadTypeLib(libnam, (LPTYPELIB *)&pTypeLib); SysFreeString(libnam); } if(SUCCEEDED(result)) { result=ITypeLib2_GetTypeInfoOfGuid((LPTYPELIB)pTypeLib, &pRefType->guid, ppTInfo); pRefType->pImpTLInfo->pImpTypeLib = pTypeLib; ITypeLib2_AddRef((ITypeLib*) pTypeLib); } } } } TRACE("(%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( ITypeInfo2 *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) { ICOM_THIS( ITypeInfoImpl, iface); FIXME("(%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( ITypeInfo2 *iface, IUnknown *pUnk, REFIID riid, VOID **ppvObj) { ICOM_THIS( ITypeInfoImpl, iface); FIXME("(%p) stub!\n", This); return S_OK; } /* ITypeInfo::GetMops * * Retrieves marshaling information. */ static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid, BSTR *pBstrMops) { ICOM_THIS( ITypeInfoImpl, iface); FIXME("(%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( ITypeInfo2 *iface, ITypeLib * *ppTLib, UINT *pIndex) { ICOM_THIS( ITypeInfoImpl, iface); if (!pIndex) return E_INVALIDARG; *ppTLib=(LPTYPELIB )(This->pTypeLib); *pIndex=This->index; ITypeLib2_AddRef(*ppTLib); TRACE("(%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( ITypeInfo2 *iface, TYPEATTR* pTypeAttr) { ICOM_THIS( ITypeInfoImpl, iface); TRACE("(%p)->(%p)\n", This, pTypeAttr); return S_OK; } /* ITypeInfo::ReleaseFuncDesc * * Releases a FUNCDESC previously returned by GetFuncDesc. * */ static HRESULT WINAPI ITypeInfo_fnReleaseFuncDesc( ITypeInfo2 *iface, FUNCDESC *pFuncDesc) { ICOM_THIS( ITypeInfoImpl, iface); TRACE("(%p)->(%p)\n", This, pFuncDesc); return S_OK; } /* ITypeInfo::ReleaseVarDesc * * Releases a VARDESC previously returned by GetVarDesc. */ static HRESULT WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface, VARDESC *pVarDesc) { ICOM_THIS( ITypeInfoImpl, iface); TRACE("(%p)->(%p)\n", This, pVarDesc); return S_OK; } /* ITypeInfo2::GetTypeKind * * Returns the TYPEKIND enumeration quickly, without doing any allocations. * */ static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface, TYPEKIND *pTypeKind) { ICOM_THIS( ITypeInfoImpl, iface); *pTypeKind=This->TypeAttr.typekind; TRACE("(%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( ITypeInfo2 * iface, UINT *pTypeFlags) { ICOM_THIS( ITypeInfoImpl, iface); *pTypeFlags=This->TypeAttr.wTypeFlags; TRACE("(%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( ITypeInfo2 * iface, MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex) { ICOM_THIS( ITypeInfoImpl, iface); TLBFuncDesc *pFuncInfo; int i; HRESULT result; /* FIXME: should check for invKind??? */ for(i=0, pFuncInfo=This->funclist;pFuncInfo && memid != pFuncInfo->funcdesc.memid; i++, pFuncInfo=pFuncInfo->next); if(pFuncInfo){ *pFuncIndex=i; result= S_OK; }else{ *pFuncIndex=0; result=E_INVALIDARG; } TRACE("(%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( ITypeInfo2 * iface, MEMBERID memid, UINT *pVarIndex) { ICOM_THIS( ITypeInfoImpl, iface); TLBVarDesc *pVarInfo; int i; HRESULT result; for(i=0, pVarInfo=This->varlist; pVarInfo && memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next) ; if(pVarInfo){ *pVarIndex=i; result= S_OK; }else{ *pVarIndex=0; result=E_INVALIDARG; } TRACE("(%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( ITypeInfo2 * iface, REFGUID guid, VARIANT *pVarVal) { ICOM_THIS( ITypeInfoImpl, iface); TLBCustData *pCData; for(pCData=This->pCustData; pCData; pCData = pCData->next) if( IsEqualIID(guid, &pCData->guid)) break; TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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( ITypeInfo2 * iface, UINT index, REFGUID guid, VARIANT *pVarVal) { ICOM_THIS( ITypeInfoImpl, 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; TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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( ITypeInfo2 * iface, UINT indexFunc, UINT indexParam, REFGUID guid, VARIANT *pVarVal) { ICOM_THIS( ITypeInfoImpl, 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 && indexParamfuncdesc.cParams) for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData; pCData = pCData->next) if( IsEqualIID(guid, &pCData->guid)) break; TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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( ITypeInfo2 * iface, UINT index, REFGUID guid, VARIANT *pVarVal) { ICOM_THIS( ITypeInfoImpl, 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; } } TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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( ITypeInfo2 * iface, UINT index, REFGUID guid, VARIANT *pVarVal) { ICOM_THIS( ITypeInfoImpl, 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; } } TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), 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( ITypeInfo2 * iface, MEMBERID memid, LCID lcid, BSTR *pbstrHelpString, DWORD *pdwHelpStringContext, BSTR *pbstrHelpStringDll) { ICOM_THIS( ITypeInfoImpl, iface); TLBFuncDesc * pFDesc; TLBVarDesc * pVDesc; TRACE("(%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=SysAllocString(This->Name); if(pdwHelpStringContext) *pdwHelpStringContext=This->dwHelpStringContext; if(pbstrHelpStringDll) *pbstrHelpStringDll= SysAllocString(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=SysAllocString(pFDesc->HelpString); if(pdwHelpStringContext) *pdwHelpStringContext=pFDesc->HelpStringContext; if(pbstrHelpStringDll) *pbstrHelpStringDll= SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ return S_OK; } for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) if(pVDesc->vardesc.memid==memid){ if(pbstrHelpString) *pbstrHelpString=SysAllocString(pVDesc->HelpString); if(pdwHelpStringContext) *pdwHelpStringContext=pVDesc->HelpStringContext; if(pbstrHelpStringDll) *pbstrHelpStringDll= SysAllocString(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( ITypeInfo2 * iface, CUSTDATA *pCustData) { ICOM_THIS( ITypeInfoImpl, iface); TLBCustData *pCData; int i; TRACE("(%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(" 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( ITypeInfo2 * iface, UINT index, CUSTDATA *pCustData) { ICOM_THIS( ITypeInfoImpl, iface); TLBCustData *pCData; TLBFuncDesc * pFDesc; int i; TRACE("(%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(" 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( ITypeInfo2 * iface, UINT indexFunc, UINT indexParam, CUSTDATA *pCustData) { ICOM_THIS( ITypeInfoImpl, iface); TLBCustData *pCData=NULL; TLBFuncDesc * pFDesc; int i; TRACE("(%p) index %d\n", This, indexFunc); for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++, pFDesc=pFDesc->next) ; if(pFDesc && indexParam >=0 && indexParamfuncdesc.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(" 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( ITypeInfo2 * iface, UINT index, CUSTDATA *pCustData) { ICOM_THIS( ITypeInfoImpl, iface); TLBCustData *pCData; TLBVarDesc * pVDesc; int i; TRACE("(%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(" 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( ITypeInfo2 * iface, UINT index, CUSTDATA *pCustData) { ICOM_THIS( ITypeInfoImpl, iface); TLBCustData *pCData; TLBRefType * pRDesc; int i; TRACE("(%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(" OUT OF MEMORY! \n"); return E_OUTOFMEMORY; } return S_OK; } return TYPE_E_ELEMENTNOTFOUND; } static ICOM_VTABLE(ITypeInfo2) tinfvt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE 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, };