oleaut32: Implement ITypeInfo2::GetFuncDesc.
authorAndrew Eikum <aeikum@codeweavers.com>
Fri, 20 Aug 2010 19:59:25 +0000 (14:59 -0500)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 23 Aug 2010 09:51:33 +0000 (11:51 +0200)
dlls/oleaut32/tests/typelib.c
dlls/oleaut32/typelib2.c

index 63b982bb3b9f30c3d76532fc15b6cac4b21c4997..a201550f17a83b58945d50d27b1e0dc56aea7058 100644 (file)
@@ -1073,6 +1073,7 @@ static void test_CreateTypeLib(void) {
     static OLECHAR dualW[] = {'d','u','a','l',0};
     static OLECHAR coclassW[] = {'c','o','c','l','a','s','s',0};
     static WCHAR defaultW[] = {'d','e','f','a','u','l','t',0x3213,0};
+    static WCHAR defaultQW[] = {'d','e','f','a','u','l','t','?',0};
     static OLECHAR func1W[] = {'f','u','n','c','1',0};
     static OLECHAR func2W[] = {'f','u','n','c','2',0};
     static OLECHAR prop1W[] = {'P','r','o','p','1',0};
@@ -1093,8 +1094,8 @@ static void test_CreateTypeLib(void) {
     ITypeLib *tl, *stdole;
     ITypeInfo *interface1, *interface2, *dual, *unknown, *dispatch, *ti;
     ITypeInfo2 *ti2;
-    FUNCDESC funcdesc;
-    ELEMDESC elemdesc[5];
+    FUNCDESC funcdesc, *pfuncdesc;
+    ELEMDESC elemdesc[5], *edesc;
     PARAMDESCEX paramdescex;
     TYPEDESC typedesc1, typedesc2;
     TYPEATTR *typeattr;
@@ -1226,6 +1227,8 @@ static void test_CreateTypeLib(void) {
     hres = ITypeInfo_GetRefTypeOfImplType(interface1, -1, &hreftype);
     ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
 
+    ICreateTypeInfo_QueryInterface(createti, &IID_ITypeInfo2, (void**)&ti2);
+
     memset(&funcdesc, 0, sizeof(FUNCDESC));
     funcdesc.funckind = FUNC_PUREVIRTUAL;
     funcdesc.invkind = INVOKE_PROPERTYGET;
@@ -1242,6 +1245,32 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 0, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 0, NULL);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
+    hres = ITypeInfo2_GetFuncDesc(ti2, 1, &pfuncdesc);
+    ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
+
+    hres = ITypeInfo2_GetFuncDesc(ti2, 0, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam == NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_PROPERTYGET, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 0, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 12 ||
+            broken(pfuncdesc->oVft == 24) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_BSTR, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     hres = ICreateTypeInfo_SetFuncHelpContext(createti, 0, 0xabcdefab);
     ok(hres == S_OK, "got %08x\n", hres);
 
@@ -1277,6 +1306,30 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 1, propname, 2);
     ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 1, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_PROPERTYPUT, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 16 ||
+            broken(pfuncdesc->oVft == 28) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_BSTR, "got: %d\n", edesc->tdesc.vt);
+    ok(edesc->idldesc.wIDLFlags == IDLFLAG_FIN, "got: %x\n", edesc->idldesc.wIDLFlags);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
 
     funcdesc.invkind = INVOKE_PROPERTYPUTREF;
     hres = ICreateTypeInfo_AddFuncDesc(createti, 0, &funcdesc);
@@ -1295,6 +1348,26 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 1, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 1, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 1, "got %d\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam == NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 0, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 16 ||
+            broken(pfuncdesc->oVft == 28), /* xp64 */
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     funcdesc.memid = MEMBERID_NIL;
     hres = ICreateTypeInfo_AddFuncDesc(createti, 1, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
@@ -1321,6 +1394,37 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 3, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 3, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010003, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 24 ||
+            broken(pfuncdesc->oVft == 36) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_INT, "got: %d\n", edesc->tdesc.vt);
+    ok(edesc->paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", edesc->paramdesc.wParamFlags);
+    ok(edesc->paramdesc.pparamdescex != NULL, "got: %p\n", edesc->paramdesc.pparamdescex);
+    ok(edesc->paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            edesc->paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue) == VT_I4, "got: %d\n",
+            V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue));
+    ok(V_I4(&edesc->paramdesc.pparamdescex->varDefaultValue) == 0x123, "got: 0x%x\n",
+            V_I4(&edesc->paramdesc.pparamdescex->varDefaultValue));
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     U(elemdesc[0]).idldesc.dwReserved = 0;
     U(elemdesc[0]).idldesc.wIDLFlags = IDLFLAG_FIN;
     elemdesc[1].tdesc.vt = VT_UI2;
@@ -1332,6 +1436,42 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 3, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 3, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010009, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 2, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 24 ||
+            broken(pfuncdesc->oVft == 36) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_INT, "got: %d\n", edesc->tdesc.vt);
+    ok(edesc->paramdesc.wParamFlags == PARAMFLAG_FIN, "got: 0x%x\n", edesc->paramdesc.wParamFlags);
+    ok(edesc->paramdesc.pparamdescex == NULL, "got: %p\n", edesc->paramdesc.pparamdescex);
+
+    edesc = pfuncdesc->lprgelemdescParam + 1;
+    ok(edesc->tdesc.vt == VT_UI2, "got: %d\n", edesc->tdesc.vt);
+    ok(edesc->paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", edesc->paramdesc.wParamFlags);
+    ok(edesc->paramdesc.pparamdescex != NULL, "got: %p\n", edesc->paramdesc.pparamdescex);
+    ok(edesc->paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            edesc->paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue) == VT_UI2, "got: %d\n",
+            V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue));
+    ok(V_UI2(&edesc->paramdesc.pparamdescex->varDefaultValue) == 0xFFFF, "got: 0x%x\n",
+            V_UI2(&edesc->paramdesc.pparamdescex->varDefaultValue));
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     U(elemdesc[0]).paramdesc.wParamFlags = PARAMFLAG_FHASDEFAULT;
     U(elemdesc[0]).paramdesc.pparamdescex = &paramdescex;
     elemdesc[1].tdesc.vt = VT_INT;
@@ -1347,6 +1487,50 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 3, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 3, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x6001000b, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 2, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 24 ||
+            broken(pfuncdesc->oVft == 36) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_BSTR, "got: %d\n", edesc->tdesc.vt);
+    ok(edesc->paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", edesc->paramdesc.wParamFlags);
+    ok(edesc->paramdesc.pparamdescex != NULL, "got: %p\n", edesc->paramdesc.pparamdescex);
+    ok(edesc->paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            edesc->paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue) == VT_BSTR, "got: %d\n",
+            V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue));
+    ok(!lstrcmpW(V_BSTR(&edesc->paramdesc.pparamdescex->varDefaultValue), defaultQW),
+            "got: %s\n",
+            wine_dbgstr_w(V_BSTR(&edesc->paramdesc.pparamdescex->varDefaultValue)));
+
+    edesc = pfuncdesc->lprgelemdescParam + 1;
+    ok(edesc->tdesc.vt == VT_BSTR, "got: %d\n", edesc->tdesc.vt);
+    ok(edesc->paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", edesc->paramdesc.wParamFlags);
+    ok(edesc->paramdesc.pparamdescex != NULL, "got: %p\n", edesc->paramdesc.pparamdescex);
+    ok(edesc->paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            edesc->paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue) == VT_BSTR, "got: %d\n",
+            V_VT(&edesc->paramdesc.pparamdescex->varDefaultValue));
+    ok(!lstrcmpW(V_BSTR(&edesc->paramdesc.pparamdescex->varDefaultValue), defaultQW),
+            "got: %s\n",
+            wine_dbgstr_w(V_BSTR(&edesc->paramdesc.pparamdescex->varDefaultValue)));
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     hres = ITypeInfo_GetDocumentation(interface1, 0, &name, &docstring, &helpcontext, &helpfile);
     ok(hres == S_OK, "got %08x\n", hres);
     ok(name == NULL, "name != NULL\n");
@@ -1383,6 +1567,7 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 3, names1, 3);
     ok(hres == TYPE_E_AMBIGUOUSNAME, "got %08x\n", hres);
 
+    ITypeInfo2_Release(ti2);
     ICreateTypeInfo_Release(createti);
 
     hres = ICreateTypeLib_CreateTypeInfo(createtl, interface1W, TKIND_INTERFACE, &createti);
index 77f072ab767e1292d1c64e923abedf9709f0e8bf..90cee432843c31980df3d48f29d1b76e67c39489 100644 (file)
@@ -1309,6 +1309,31 @@ static int ctl2_encode_typedesc(
     return 0;
 }
 
+/****************************************************************************
+ *     ctl2_decode_typedesc
+ *
+ *  Decodes a type description from an ICreateTypeLib2Impl.
+ *
+ * RETURNS
+ *
+ *  Success: S_OK.
+ *  Failure: HRESULT error code.
+ */
+static HRESULT ctl2_decode_typedesc(
+       ICreateTypeLib2Impl *This, /* [I] The type library from which to decode the TYPEDESC. */
+       int encoded_tdesc,         /* [I] The encoded type description. */
+       TYPEDESC *tdesc)           /* [O] The decoded type description. */
+{
+    if (encoded_tdesc & 0x80000000) {
+        tdesc->vt = encoded_tdesc & VT_TYPEMASK;
+        tdesc->u.lptdesc = NULL;
+        return S_OK;
+    }
+
+    FIXME("unable to decode typedesc: %08x\n", encoded_tdesc);
+    return E_NOTIMPL;
+}
+
 /****************************************************************************
  *     ctl2_find_nth_reference
  *
@@ -3144,8 +3169,101 @@ static HRESULT WINAPI ITypeInfo2_fnGetFuncDesc(
         UINT index,
         FUNCDESC** ppFuncDesc)
 {
-    FIXME("(%p,%d,%p), stub!\n", iface, index, ppFuncDesc);
-    return E_OUTOFMEMORY;
+    ICreateTypeInfo2Impl *This = impl_from_ITypeInfo2(iface);
+    int i, *typedata, num_defaults = 0, hdr_len, tail, has_defaults;
+    CyclicList *desc;
+    HRESULT hres;
+
+    TRACE("(%p,%d,%p), semi-stub\n", iface, index, ppFuncDesc);
+
+    if (!ppFuncDesc)
+        return E_INVALIDARG;
+
+    if (index >= This->typeinfo->cElement)
+        return TYPE_E_ELEMENTNOTFOUND;
+
+    hres = ICreateTypeInfo2_LayOut((ICreateTypeInfo2*)This);
+    if (FAILED(hres))
+        return hres;
+
+    desc = This->typedata->next;
+    for (i = index; i >= 0; ) {
+        desc = desc->next;
+        if (desc->type == CyclicListFunc)
+            --i;
+    }
+
+    typedata = desc->u.data;
+
+    *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FUNCDESC));
+    if (!*ppFuncDesc)
+        return E_OUTOFMEMORY;
+
+    (*ppFuncDesc)->memid = desc->indice;
+    (*ppFuncDesc)->lprgscode = NULL; /* FIXME: Unimplemented */
+    (*ppFuncDesc)->funckind = typedata[4] & 0x7;
+    (*ppFuncDesc)->invkind = (typedata[4] >> 3) & 0xF;
+    (*ppFuncDesc)->callconv = (typedata[4] >> 8) & 0xF;
+    (*ppFuncDesc)->cParams = typedata[5];
+    (*ppFuncDesc)->cParamsOpt = 0; /* FIXME: Unimplemented*/
+    (*ppFuncDesc)->oVft = typedata[3] & 0xFFFF;
+    if ((*ppFuncDesc)->oVft)
+        --(*ppFuncDesc)->oVft;
+    (*ppFuncDesc)->cScodes = 0; /* FIXME: Unimplemented*/
+    hres = ctl2_decode_typedesc(This->typelib, typedata[1],
+            &(*ppFuncDesc)->elemdescFunc.tdesc);
+    if (FAILED(hres)) {
+        HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
+        return hres;
+    }
+    (*ppFuncDesc)->wFuncFlags = typedata[2];
+
+    has_defaults = typedata[4] & 0x1000;
+    tail = typedata[5] * (has_defaults ? 16 : 12);
+    hdr_len = ((typedata[0] & 0xFFFF) - tail) / sizeof(int);
+
+    if ((*ppFuncDesc)->cParams > 0) {
+        (*ppFuncDesc)->lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (*ppFuncDesc)->cParams * sizeof(ELEMDESC));
+        if (!(*ppFuncDesc)->lprgelemdescParam) {
+            HeapFree(GetProcessHeap(), 0, *ppFuncDesc);
+            return E_OUTOFMEMORY;
+        }
+        if (has_defaults) {
+            num_defaults = (*ppFuncDesc)->cParams;
+
+            for (i = 0; i < num_defaults; ++i) {
+                if (typedata[hdr_len + i] != 0xFFFFFFFF) {
+                    (*ppFuncDesc)->lprgelemdescParam[i].u.paramdesc.wParamFlags |= PARAMFLAG_FHASDEFAULT;
+
+                    (*ppFuncDesc)->lprgelemdescParam[i].u.paramdesc.pparamdescex = HeapAlloc(GetProcessHeap(), 0, sizeof(PARAMDESCEX));
+                    if (!(*ppFuncDesc)->lprgelemdescParam[i].u.paramdesc.pparamdescex) {
+                        ITypeInfo2_ReleaseFuncDesc(iface, *ppFuncDesc);
+                        return E_OUTOFMEMORY;
+                    }
+
+                    (*ppFuncDesc)->lprgelemdescParam[i].u.paramdesc.pparamdescex->cBytes = sizeof(PARAMDESCEX);
+                    hres = ctl2_decode_variant(This->typelib, typedata[hdr_len + i],
+                            &(*ppFuncDesc)->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
+                    if (FAILED(hres)) {
+                        ITypeInfo2_ReleaseFuncDesc(iface, *ppFuncDesc);
+                        return hres;
+                    }
+                }
+            }
+        }
+
+        for (i = 0; i < (*ppFuncDesc)->cParams; ++i) {
+            hres = ctl2_decode_typedesc(This->typelib, typedata[hdr_len + num_defaults + (i * 3)],
+                    &((*ppFuncDesc)->lprgelemdescParam + i)->tdesc);
+            if (FAILED(hres)) {
+                ITypeInfo2_ReleaseFuncDesc(iface, *ppFuncDesc);
+                return hres;
+            }
+            (*ppFuncDesc)->lprgelemdescParam[i].u.paramdesc.wParamFlags = typedata[hdr_len + num_defaults + (i * 3) + 2];
+        }
+    }
+
+    return S_OK;
 }
 
 /******************************************************************************