+static SIZE_T TLB_SizeElemDesc( const ELEMDESC *elemdesc )
+{
+ SIZE_T size = TLB_SizeTypeDesc(&elemdesc->tdesc, FALSE);
+ if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+ size += sizeof(*elemdesc->u.paramdesc.pparamdescex);
+ return size;
+}
+
+static HRESULT TLB_CopyElemDesc( const ELEMDESC *src, ELEMDESC *dest, char **buffer )
+{
+ memcpy(dest, src, sizeof(ELEMDESC));
+ *buffer = TLB_CopyTypeDesc(&dest->tdesc, &src->tdesc, *buffer);
+ if (src->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+ {
+ const PARAMDESCEX *pparamdescex_src = src->u.paramdesc.pparamdescex;
+ PARAMDESCEX *pparamdescex_dest = dest->u.paramdesc.pparamdescex = (PARAMDESCEX *)*buffer;
+ *buffer += sizeof(PARAMDESCEX);
+ memcpy(pparamdescex_dest, pparamdescex_src, sizeof(PARAMDESCEX));
+ VariantInit(&pparamdescex_dest->varDefaultValue);
+ return VariantCopy(&pparamdescex_dest->varDefaultValue,
+ (VARIANTARG *)&pparamdescex_src->varDefaultValue);
+ }
+ else
+ dest->u.paramdesc.pparamdescex = NULL;
+ return S_OK;
+}
+
+static void TLB_FreeElemDesc( ELEMDESC *elemdesc )
+{
+ if (elemdesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
+ VariantClear(&elemdesc->u.paramdesc.pparamdescex->varDefaultValue);
+}
+
+static HRESULT TLB_AllocAndInitFuncDesc( const FUNCDESC *src, FUNCDESC **dest_ptr, BOOL dispinterface )
+{
+ FUNCDESC *dest;
+ char *buffer;
+ SIZE_T size = sizeof(*src);
+ SHORT i;
+ HRESULT hr;
+
+ size += sizeof(*src->lprgscode) * src->cScodes;
+ size += TLB_SizeElemDesc(&src->elemdescFunc);
+ for (i = 0; i < src->cParams; i++)
+ {
+ size += sizeof(ELEMDESC);
+ size += TLB_SizeElemDesc(&src->lprgelemdescParam[i]);
+ }
+
+ dest = (FUNCDESC *)SysAllocStringByteLen(NULL, size);
+ if (!dest) return E_OUTOFMEMORY;
+
+ memcpy(dest, src, sizeof(FUNCDESC));
+ buffer = (char *)(dest + 1);
+
+ dest->lprgscode = (SCODE *)buffer;
+ memcpy(dest->lprgscode, src->lprgscode, sizeof(*src->lprgscode) * src->cScodes);
+ buffer += sizeof(*src->lprgscode) * src->cScodes;
+
+ hr = TLB_CopyElemDesc(&src->elemdescFunc, &dest->elemdescFunc, &buffer);
+ if (FAILED(hr))
+ {
+ SysFreeString((BSTR)dest);
+ return hr;
+ }
+
+ dest->lprgelemdescParam = (ELEMDESC *)buffer;
+ buffer += sizeof(ELEMDESC) * src->cParams;
+ for (i = 0; i < src->cParams; i++)
+ {
+ hr = TLB_CopyElemDesc(&src->lprgelemdescParam[i], &dest->lprgelemdescParam[i], &buffer);
+ if (FAILED(hr))
+ break;
+ }
+ if (FAILED(hr))
+ {
+ /* undo the above actions */
+ for (i = i - 1; i >= 0; i--)
+ TLB_FreeElemDesc(&dest->lprgelemdescParam[i]);
+ TLB_FreeElemDesc(&dest->elemdescFunc);
+ SysFreeString((BSTR)dest);
+ return hr;
+ }
+
+ /* special treatment for dispinterfaces: this makes functions appear
+ * to return their [retval] value when it is really returning an
+ * HRESULT */
+ if (dispinterface && dest->elemdescFunc.tdesc.vt == VT_HRESULT)
+ {
+ if (dest->cParams &&
+ (dest->lprgelemdescParam[dest->cParams - 1].u.paramdesc.wParamFlags & PARAMFLAG_FRETVAL))
+ {
+ ELEMDESC *elemdesc = &dest->lprgelemdescParam[dest->cParams - 1];
+ if (elemdesc->tdesc.vt != VT_PTR)
+ {
+ ERR("elemdesc should have started with VT_PTR instead of:\n");
+ if (ERR_ON(ole))
+ dump_ELEMDESC(elemdesc);
+ return E_UNEXPECTED;
+ }
+
+ /* copy last parameter to the return value. we are using a flat
+ * buffer so there is no danger of leaking memory in
+ * elemdescFunc */
+ dest->elemdescFunc.tdesc = *elemdesc->tdesc.u.lptdesc;
+
+ /* remove the last parameter */
+ dest->cParams--;
+ }
+ else
+ /* otherwise this function is made to appear to have no return
+ * value */
+ dest->elemdescFunc.tdesc.vt = VT_VOID;
+
+ }
+
+ *dest_ptr = dest;
+ return S_OK;
+}
+
+HRESULT ITypeInfoImpl_GetInternalFuncDesc( ITypeInfo *iface, UINT index, const FUNCDESC **ppFuncDesc )
+{
+ ITypeInfoImpl *This = (ITypeInfoImpl *)iface;
+ const TLBFuncDesc *pFDesc;
+ int i;
+
+ for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next)
+ ;
+
+ if (pFDesc)
+ {
+ *ppFuncDesc = &pFDesc->funcdesc;
+ return S_OK;
+ }
+
+ return E_INVALIDARG;
+}
+