+static HRESULT userdefined_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
+{
+ HRESULT hr = S_OK;
+ ITypeInfo *tinfo2 = NULL;
+ TYPEATTR *tattr = NULL;
+
+ hr = ITypeInfo_GetRefTypeInfo(tinfo, tdesc->u.hreftype, &tinfo2);
+ if (hr)
+ {
+ ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, "
+ "hr = 0x%08lx\n",
+ tdesc->u.hreftype, hr);
+ return hr;
+ }
+ hr = ITypeInfo_GetTypeAttr(tinfo2, &tattr);
+ if (hr)
+ {
+ ERR("ITypeInfo_GetTypeAttr failed, hr = 0x%08lx\n", hr);
+ ITypeInfo_Release(tinfo2);
+ return hr;
+ }
+
+ switch (tattr->typekind)
+ {
+ case TKIND_ENUM:
+ *vt |= VT_INT;
+ break;
+
+ case TKIND_ALIAS:
+ tdesc = &tattr->tdescAlias;
+ hr = typedescvt_to_variantvt(tinfo2, &tattr->tdescAlias, vt);
+ break;
+
+ case TKIND_INTERFACE:
+ if (IsEqualIID(&IID_IDispatch, &tattr->guid))
+ *vt |= VT_DISPATCH;
+ else
+ *vt |= VT_UNKNOWN;
+ break;
+
+ case TKIND_DISPATCH:
+ *vt |= VT_DISPATCH;
+ break;
+
+ case TKIND_RECORD:
+ FIXME("TKIND_RECORD unhandled.\n");
+ hr = E_NOTIMPL;
+ break;
+
+ case TKIND_UNION:
+ FIXME("TKIND_RECORD unhandled.\n");
+ hr = E_NOTIMPL;
+ break;
+
+ default:
+ FIXME("TKIND %d unhandled.\n",tattr->typekind);
+ hr = E_NOTIMPL;
+ break;
+ }
+ ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
+ ITypeInfo_Release(tinfo2);
+ return hr;
+}
+
+static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, TYPEDESC *tdesc, VARTYPE *vt)
+{
+ HRESULT hr = S_OK;
+
+ /* enforce only one level of pointer indirection */
+ if (!(*vt & VT_BYREF) && (tdesc->vt == VT_PTR))
+ {
+ tdesc = tdesc->u.lptdesc;
+
+ /* munch VT_PTR -> VT_USERDEFINED(interface) into VT_UNKNOWN or
+ * VT_DISPATCH and VT_PTR -> VT_PTR -> VT_USERDEFINED(interface) into
+ * VT_BYREF|VT_DISPATCH or VT_BYREF|VT_UNKNOWN */
+ if ((tdesc->vt == VT_USERDEFINED) ||
+ ((tdesc->vt == VT_PTR) && (tdesc->u.lptdesc->vt == VT_USERDEFINED)))
+ {
+ VARTYPE vt_userdefined = 0;
+ TYPEDESC *tdesc_userdefined = tdesc;
+ if (tdesc->vt == VT_PTR)
+ {
+ vt_userdefined = VT_BYREF;
+ tdesc_userdefined = tdesc->u.lptdesc;
+ }
+ hr = userdefined_to_variantvt(tinfo, tdesc_userdefined, &vt_userdefined);
+ if ((hr == S_OK) &&
+ (((vt_userdefined & VT_TYPEMASK) == VT_UNKNOWN) ||
+ ((vt_userdefined & VT_TYPEMASK) == VT_DISPATCH)))
+ {
+ *vt |= vt_userdefined;
+ return S_OK;
+ }
+ }
+ *vt = VT_BYREF;
+ }
+
+ switch (tdesc->vt)
+ {
+ case VT_HRESULT:
+ *vt |= VT_ERROR;
+ break;
+ case VT_USERDEFINED:
+ hr = userdefined_to_variantvt(tinfo, tdesc, vt);
+ break;
+ case VT_PTR:
+ ERR("cannot convert VT_PTR into variant VT\n");
+ hr = E_FAIL;
+ break;
+ default:
+ *vt |= tdesc->vt;
+ break;
+ }
+ return hr;
+}
+