Merged the two serializer and unserializer functions into one, cleaned
them up.
VT_PTR: Handle NULL pointers by sending a cookie.
Added support for: VT_CARRAY, VT_DISPATCH, TKIND_RECORD, VT_VOID,
VT_UI1, VT_UI2, VT_ERROR, VT_UI4, VT_UINT.
Added a custom serializer for DISPPARAMS struct.

diff --git a/dlls/oleaut32/tmarshal.c b/dlls/oleaut32/tmarshal.c
index 2644dc4..3d6b9aa 100644
--- a/dlls/oleaut32/tmarshal.c
+++ b/dlls/oleaut32/tmarshal.c
@@ -43,6 +43,8 @@
 #include "ntddk.h"
 
 static const WCHAR riidW[5] = {'r','i','i','d',0};
+static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};
+static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
@@ -357,60 +359,146 @@
     TMProxyImpl_Disconnect
 };
 
+/* how much space do we use on stack in DWORD steps. */
+static int const
+_argsize(DWORD vt) {
+    switch (vt) {
+    case VT_VARIANT:
+	return (sizeof(VARIANT)+3)/sizeof(DWORD);
+    default:
+	return 1;
+    }
+}
+
+static int
+_xsize(TYPEDESC *td) {
+    switch (td->vt) {
+    case VT_VARIANT:
+	return sizeof(VARIANT)+3;
+    case VT_CARRAY: {
+	int i, arrsize = 1;
+	ARRAYDESC *adesc = td->u.lpadesc;
+
+	for (i=0;i<adesc->cDims;i++)
+	    arrsize *= adesc->rgbounds[i].cElements;
+	return arrsize*_xsize(&adesc->tdescElem);
+    }
+    case VT_UI2:
+    case VT_I2:
+	return 2;
+    case VT_UI1:
+    case VT_I1:
+	return 1;
+    default:
+	return 4;
+    }
+}
+
 static HRESULT
-marshall_param(
-    ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
+serialize_param(
+    ITypeInfo		*tinfo,
+    BOOL		writeit,
+    BOOL		debugout,
+    BOOL		dealloc,
+    TYPEDESC		*tdesc,
+    DWORD		*arg,
+    marshal_state	*buf
 ) {
-    int relaydeb = TRACE_ON(olerelay);
-    HRESULT	hres;
+    HRESULT hres = S_OK;
 
-    if (!tdesc) tdesc = &(elem->tdesc);
+    TRACE("(tdesc.vt %d)\n",tdesc->vt);
+
     switch (tdesc->vt) {
-    case VT_NULL:
+    case VT_EMPTY: /* nothing. empty variant for instance */
 	return S_OK;
-    case VT_BSTR: {	/* DWORD size, string data */
+    case VT_BOOL:
+    case VT_ERROR:
+    case VT_UI4:
+    case VT_UINT:
+    case VT_I4:
+    case VT_UI2:
+    case VT_UI1:
+	hres = S_OK;
+	if (debugout) MESSAGE("%lx",*arg);
+	if (writeit)
+	    hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
+	return hres;
+    case VT_VARIANT: {
+	TYPEDESC	tdesc2;
+	VARIANT		*vt = (VARIANT*)arg;
+	DWORD		vttype = V_VT(vt);
 
-	    if (*arg) {
+	if (debugout) MESSAGE("Vt(%ld)(",vttype);
+	tdesc2.vt = vttype;
+	if (writeit) {
+	    hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
+	    if (hres) return hres;
+	}
+	/* need to recurse since we need to free the stuff */
+	hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);
+	if (debugout) MESSAGE(")");
+	return hres;
+    }
+    case VT_BSTR: {
+	if (debugout) {
+	    if (arg)
+		    MESSAGE("%s",debugstr_w((BSTR)*arg));
+	    else
+		    MESSAGE("<bstr NULL>");
+	}
+	if (writeit) {
+	    if (!*arg) {
+		DWORD fakelen = -1;
+		hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
+		if (hres)
+		    return hres;
+	    } else {
 		DWORD *bstr = ((DWORD*)(*arg))-1;
 
-		if (relaydeb) MESSAGE("%s",debugstr_w((LPWSTR)(bstr+1)));
-		return xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
-	    } else {
-		DWORD xnull = 0;
-
-		return xbuf_add(buf,(LPBYTE)&xnull,sizeof(xnull));
+		hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
+		if (hres)
+		    return hres;
 	    }
 	}
-    case VT_BOOL:
-    case VT_I4:
-	if (relaydeb) MESSAGE("%ld",*arg);
-	return xbuf_add(buf,(LPBYTE)arg,4);
-    case VT_VARIANT: {
-	/* We use ourselves to marshal the value further */
-	TYPEDESC tdesc2;
-	VARIANT *vt = (VARIANT*)arg;
-	DWORD vttype = V_VT(vt);
-
-	hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
-	if (hres) return hres;
-	tdesc2.vt = vttype;
-	if (relaydeb) MESSAGE("Vt %ld ",vttype);
-	/* shield your eyes, bad pointer voodoo below */
-	return marshall_param(tinfo,elem,&tdesc2,(DWORD*)&(V_I4(vt)),buf);
+	if (dealloc && arg)
+	    SysFreeString((BSTR)arg);
+	return S_OK;
     }
-    case VT_PTR:
-	return marshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf);
-    case VT_VOID:
-	hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)arg);
-	if (hres) {
-	    FIXME("Failed unmarshaling VT_VOID with guid %s?\n",debugstr_guid(&(buf->iid)));
+    case VT_PTR: {
+	DWORD cookie;
+
+	if (debugout) MESSAGE("*");
+	if (writeit) {
+	    cookie = *arg ? 0x42424242 : 0;
+	    hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
+	    if (hres)
+		return hres;
 	}
+	if (!*arg) {
+	    if (debugout) MESSAGE("NULL");
+	    return S_OK;
+	}
+	hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
+	if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
 	return hres;
+    }
+    case VT_UNKNOWN:
+	if (debugout) MESSAGE("unk(0x%lx)",*arg);
+	if (writeit)
+	    hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
+	return hres;
+    case VT_DISPATCH:
+	if (debugout) MESSAGE("idisp(0x%lx)",*arg);
+	if (writeit)
+	    hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
+	return hres;
+    case VT_VOID:
+	if (debugout) MESSAGE("<void>");
+	return S_OK;
     case VT_USERDEFINED: {
 	ITypeInfo	*tinfo2;
 	TYPEATTR	*tattr;
 
-	/*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/
 	hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
 	if (hres) {
 	    FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
@@ -419,15 +507,53 @@
 	ITypeInfo_GetTypeAttr(tinfo2,&tattr);
 	switch (tattr->typekind) {
 	case TKIND_INTERFACE:
-	    if (relaydeb) MESSAGE("if(%p), vtbl %p",arg,(LPVOID)*arg);
-	    hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
+	    if (writeit)
+	       hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
 	    break;
-	case TKIND_RECORD:
-	    if (relaydeb) MESSAGE("record %p",arg);
-	    if (buf->thisisiid)
+	case TKIND_RECORD: {
+	    int i;
+	    if (debugout) MESSAGE("{");
+	    for (i=0;i<tattr->cVars;i++) {
+		VARDESC *vdesc;
+		ELEMDESC *elem2;
+		TYPEDESC *tdesc2;
+
+		hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
+		if (hres) {
+		    FIXME("Could not get vardesc of %d\n",i);
+		    return hres;
+		}
+		/* Need them for hack below */
+		/*
+		memset(names,0,sizeof(names));
+		hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
+		if (nrofnames > sizeof(names)/sizeof(names[0])) {
+		    ERR("Need more names!\n");
+		}
+		if (!hres && debugout)
+		    MESSAGE("%s=",debugstr_w(names[0]));
+		*/
+		elem2 = &vdesc->elemdescVar;
+		tdesc2 = &elem2->tdesc;
+		hres = serialize_param(
+		    tinfo2,
+		    writeit,
+		    debugout,
+		    dealloc,
+		    tdesc2,
+		    (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
+		    buf
+		);
+		if (hres!=S_OK)
+		    return hres;
+		if (debugout && (i<(tattr->cVars-1)))
+		    MESSAGE(",");
+	    }
+	    if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
 		memcpy(&(buf->iid),arg,sizeof(buf->iid));
-	    hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance);
+	    if (debugout) MESSAGE("}");
 	    break;
+	}
 	default:
 	    FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
 	    hres = E_FAIL;
@@ -436,85 +562,502 @@
 	ITypeInfo_Release(tinfo2);
 	return hres;
     }
-    case VT_UNKNOWN:
-        return _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
+    case VT_CARRAY: {
+	ARRAYDESC *adesc = tdesc->u.lpadesc;
+	int i, arrsize = 1;
+
+	if (debugout) MESSAGE("carr");
+	for (i=0;i<adesc->cDims;i++) {
+	    if (debugout) MESSAGE("[%ld]",adesc->rgbounds[i].cElements);
+	    arrsize *= adesc->rgbounds[i].cElements;
+	}
+	if (debugout) MESSAGE("[");
+	for (i=0;i<arrsize;i++) {
+	    hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
+	    if (hres)
+		return hres;
+	    if (debugout && (i<arrsize-1)) MESSAGE(",");
+	}
+	if (debugout) MESSAGE("]");
+	return S_OK;
+    }
     default:
-	ERR("Cannot marshal type %d\n",tdesc->vt);
-	/*dump_ELEMDESC(elem);*/
+	ERR("Unhandled marshal type %d.\n",tdesc->vt);
+	return S_OK;
+    }
+}
+
+static HRESULT
+serialize_LPVOID_ptr(
+    ITypeInfo		*tinfo,
+    BOOL		writeit,
+    BOOL		debugout,
+    BOOL		dealloc,
+    TYPEDESC		*tdesc,
+    DWORD		*arg,
+    marshal_state	*buf
+) {
+    HRESULT	hres;
+    DWORD	cookie;
+
+    if ((tdesc->vt != VT_PTR)			||
+	(tdesc->u.lptdesc->vt != VT_PTR)	||
+	(tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
+    ) {
+	FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
 	return E_FAIL;
     }
+    cookie = (*arg) ? 0x42424242: 0x0;
+    if (writeit) {
+	hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
+	if (hres)
+	    return hres;
+    }
+    if (!*arg) {
+	if (debugout) MESSAGE("<lpvoid NULL>");
+	return S_OK;
+    }
+    if (debugout)
+	MESSAGE("ppv(%p)",*(LPUNKNOWN*)*arg);
+    if (writeit) {
+	hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
+	if (hres)
+	    return hres;
+    }
+    if (dealloc)
+	HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
+    return S_OK;
+}
+
+static HRESULT
+serialize_DISPPARAM_ptr(
+    ITypeInfo		*tinfo,
+    BOOL		writeit,
+    BOOL		debugout,
+    BOOL		dealloc,
+    TYPEDESC		*tdesc,
+    DWORD		*arg,
+    marshal_state	*buf
+) {
+    DWORD	cookie;
+    HRESULT	hres;
+    DISPPARAMS	*disp;
+    int		i;
+
+    if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
+	FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
+	return E_FAIL;
+    }
+
+    cookie = *arg ? 0x42424242 : 0x0;
+    if (writeit) {
+	hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
+	if (hres)
+	    return hres;
+    }
+    if (!*arg) {
+	if (debugout) MESSAGE("<DISPPARAMS NULL>");
+	return S_OK;
+    }
+    disp = (DISPPARAMS*)*arg;
+    if (writeit) {
+	hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
+	if (hres)
+	    return hres;
+    }
+    if (debugout) MESSAGE("D{");
+    for (i=0;i<disp->cArgs;i++) {
+	TYPEDESC	vtdesc;
+
+	vtdesc.vt = VT_VARIANT;
+	serialize_param(
+	    tinfo,
+	    writeit,
+	    debugout,
+	    dealloc,
+	    &vtdesc,
+	    (DWORD*)(disp->rgvarg+i),
+	    buf
+        );
+	if (debugout && (i<disp->cArgs-1))
+	    MESSAGE(",");
+    }
+    if (dealloc)
+	HeapFree(GetProcessHeap(),0,disp->rgvarg);
+    if (writeit) {
+	hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
+	if (hres)
+	    return hres;
+    }
+    if (debugout) MESSAGE("}{");
+    for (i=0;i<disp->cNamedArgs;i++) {
+	TYPEDESC	vtdesc;
+
+	vtdesc.vt = VT_UINT;
+	serialize_param(
+	    tinfo,
+	    writeit,
+	    debugout,
+	    dealloc,
+	    &vtdesc,
+	    (DWORD*)(disp->rgdispidNamedArgs+i),
+	    buf
+	);
+	if (debugout && (i<disp->cNamedArgs-1))
+	    MESSAGE(",");
+    }
+    if (debugout) MESSAGE("}");
+    if (dealloc) {
+	HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
+	HeapFree(GetProcessHeap(),0,disp);
+    }
     return S_OK;
 }
 
 static HRESULT
-unmarshall_param(
-    ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
+deserialize_param(
+    ITypeInfo		*tinfo,
+    BOOL		readit,
+    BOOL		debugout,
+    BOOL		alloc,
+    TYPEDESC		*tdesc,
+    DWORD		*arg,
+    marshal_state	*buf
 ) {
     HRESULT hres = S_OK;
-    int relaydeb = TRACE_ON(olerelay);
 
-    if (!tdesc) tdesc = &(elem->tdesc);
-    switch (tdesc->vt) {
-    case VT_I4: {
-	DWORD x;
-	xbuf_get(buf,(LPBYTE)&x,sizeof(x));
-	*arg = x;
-	if (relaydeb) MESSAGE("%ld ",x);
-	return S_OK;
-    }
-    case VT_PTR:
-	if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
-	    (tdesc->u.lptdesc->vt != VT_VOID)
-	)
-	    hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)(*arg),buf);
-	else
-	    hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,arg,buf);
-	if (relaydeb) MESSAGE("%p ",(LPVOID)*arg);
-	return S_OK;
-    case VT_USERDEFINED: {
-	ITypeInfo	*tinfo2;
-	TYPEATTR	*tattr;
+    TRACE("vt %d at %p\n",tdesc->vt,arg);
 
-	if (relaydeb) MESSAGE("%p",arg);
-	hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
-	if (hres) {
-	    FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
+    while (1) {
+	switch (tdesc->vt) {
+	case VT_EMPTY:
+	    if (debugout) MESSAGE("<empty>");
+	    return S_OK;
+	case VT_NULL:
+	    if (debugout) MESSAGE("<null>");
+	    return S_OK;
+	case VT_VARIANT: {
+	    VARIANT	*vt = (VARIANT*)arg;
+
+	    if (readit) {
+		DWORD	vttype;
+		TYPEDESC	tdesc2;
+		hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
+		if (hres) {
+		    FIXME("vt type not read?\n");
+		    return hres;
+		}
+		memset(&tdesc2,0,sizeof(tdesc2));
+		tdesc2.vt = vttype;
+		V_VT(vt)  = vttype;
+	        if (debugout) MESSAGE("Vt(%ld)(",vttype);
+		hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);
+		MESSAGE(")");
+		return hres;
+	    } else {
+		VariantInit(vt);
+		return S_OK;
+	    }
+	}
+        case VT_ERROR:
+	case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT:
+        case VT_UI2:
+	case VT_UI1:
+	    if (readit) {
+		hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
+		if (hres) FIXME("Failed to read integer 4 byte\n");
+	    }
+	    if (debugout) MESSAGE("%lx",*arg);
+	    return hres;
+	case VT_BSTR: {
+	    WCHAR	*str;
+	    DWORD	len;
+
+	    if (readit) {
+		hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
+		if (hres) {
+		    FIXME("failed to read bstr klen\n");
+		    return hres;
+		}
+		if (len == -1) {
+		    *arg = 0;
+		    if (debugout) MESSAGE("<bstr NULL>");
+		} else {
+		    str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
+		    hres = xbuf_get(buf,(LPBYTE)str,len);
+		    if (hres) {
+			FIXME("Failed to read BSTR.\n");
+			return hres;
+		    }
+		    *arg = (DWORD)SysAllocStringLen(str,len);
+		    if (debugout) MESSAGE("%s",debugstr_w(str));
+		    HeapFree(GetProcessHeap(),0,str);
+		}
+	    } else {
+	        *arg = 0;
+	    }
+	    return S_OK;
+	}
+	case VT_PTR: {
+	    DWORD	cookie;
+	    BOOL	derefhere = 0;
+
+	    derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
+
+	    if (readit) {
+		hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
+		if (hres) {
+		    FIXME("Failed to load pointer cookie.\n");
+		    return hres;
+		}
+		if (cookie != 0x42424242) {
+		    if (debugout) MESSAGE("NULL");
+		    *arg = 0;
+		    return S_OK;
+		}
+		if (debugout) MESSAGE("*");
+	    }
+	    if (alloc) {
+		if (derefhere)
+		    *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
+	    }
+	    if (derefhere)
+		return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
+	    else
+		return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
+        }
+	case VT_UNKNOWN:
+	    /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
+	    if (alloc)
+	        *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
+	    hres = S_OK;
+	    if (readit)
+		hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
+	    if (debugout)
+		MESSAGE("unk(%p)",arg);
+	    return hres;
+	case VT_DISPATCH:
+	    hres = S_OK;
+	    if (readit)
+		hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
+	    if (debugout)
+		MESSAGE("idisp(%p)",arg);
+	    return hres;
+	case VT_VOID:
+	    if (debugout) MESSAGE("<void>");
+	    return S_OK;
+	case VT_USERDEFINED: {
+	    ITypeInfo	*tinfo2;
+	    TYPEATTR	*tattr;
+
+	    hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
+	    if (hres) {
+		FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
+		return hres;
+	    }
+	    hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
+	    if (hres) {
+		FIXME("Could not get typeattr in VT_USERDEFINED.\n");
+	    } else {
+		if (alloc)
+		    *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
+		switch (tattr->typekind) {
+		case TKIND_INTERFACE:
+		    if (readit)
+			hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
+		    break;
+		case TKIND_RECORD: {
+		    int i;
+
+		    if (debugout) MESSAGE("{");
+		    for (i=0;i<tattr->cVars;i++) {
+			VARDESC *vdesc;
+
+			hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
+			if (hres) {
+			    FIXME("Could not get vardesc of %d\n",i);
+			    return hres;
+			}
+			hres = deserialize_param(
+			    tinfo2,
+			    readit,
+			    debugout,
+			    alloc,
+			    &vdesc->elemdescVar.tdesc,
+			    (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
+			    buf
+			);
+		        if (debugout && (i<tattr->cVars-1)) MESSAGE(",");
+		    }
+		    if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
+			memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
+		    if (debugout) MESSAGE("}");
+		    break;
+		}
+		default:
+		    FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
+		    hres = E_FAIL;
+		    break;
+		}
+	    }
+	    if (hres)
+		FIXME("failed to stuballoc in TKIND_RECORD.\n");
+	    ITypeInfo_Release(tinfo2);
 	    return hres;
 	}
-	hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
-	if (hres) {
-	    FIXME("Could not get typeattr in VT_USERDEFINED.\n");
-	    return hres;
+	case VT_CARRAY: {
+	    /* arg is pointing to the start of the array. */
+	    ARRAYDESC *adesc = tdesc->u.lpadesc;
+	    int		arrsize,i;
+	    arrsize = 1;
+	    if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
+	    for (i=0;i<adesc->cDims;i++)
+		arrsize *= adesc->rgbounds[i].cElements;
+	    for (i=0;i<arrsize;i++)
+		deserialize_param(
+		    tinfo,
+		    readit,
+		    debugout,
+		    alloc,
+		    &adesc->tdescElem,
+		    (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),
+		    buf
+		);
+	    return S_OK;
 	}
-	switch (tattr->typekind) {
-	case TKIND_INTERFACE:
-	    hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
-	    break;
-	case TKIND_RECORD:
-	    hres = xbuf_get(buf,(LPBYTE)arg,tattr->cbSizeInstance);
-	    break;
 	default:
-	    hres = E_FAIL;
-	    FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
+	    ERR("No handler for VT type %d!\n",tdesc->vt);
+	    return S_OK;
 	}
-	ITypeInfo_Release(tinfo2);
+    }
+}
+
+static HRESULT
+deserialize_LPVOID_ptr(
+    ITypeInfo		*tinfo,
+    BOOL		readit,
+    BOOL		debugout,
+    BOOL		alloc,
+    TYPEDESC		*tdesc,
+    DWORD		*arg,
+    marshal_state	*buf
+) {
+    HRESULT	hres;
+    DWORD	cookie;
+
+    if ((tdesc->vt != VT_PTR)			||
+	(tdesc->u.lptdesc->vt != VT_PTR)	||
+	(tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
+    ) {
+	FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
+	return E_FAIL;
+    }
+    if (alloc)
+	*arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
+    if (readit) {
+	hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));
+	if (hres)
+	    return hres;
+	if (cookie != 0x42424242) {
+	    *(DWORD*)*arg = 0;
+	    if (debugout) MESSAGE("<lpvoid NULL>");
+	    return S_OK;
+	}
+    }
+    if (readit) {
+	hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);
+	if (hres)
+	    return hres;
+    }
+    if (debugout) MESSAGE("ppv(%p)",(LPVOID)*arg);
+    return S_OK;
+}
+
+static HRESULT
+deserialize_DISPPARAM_ptr(
+    ITypeInfo		*tinfo,
+    BOOL		readit,
+    BOOL		debugout,
+    BOOL		alloc,
+    TYPEDESC		*tdesc,
+    DWORD		*arg,
+    marshal_state	*buf
+) {
+    DWORD	cookie;
+    DISPPARAMS	*disps;
+    HRESULT	hres;
+    int		i;
+
+    if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
+	FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
+	return E_FAIL;
+    }
+    if (readit) {
+	hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
+	if (hres)
+	    return hres;
+	if (cookie == 0) {
+	    *arg = 0;
+	    if (debugout) MESSAGE("<DISPPARAMS NULL>");
+	    return S_OK;
+	}
+    }
+    if (alloc)
+	*arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));
+    disps = (DISPPARAMS*)*arg;
+    if (!readit)
+	return S_OK;
+    hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));
+    if (hres)
 	return hres;
+    if (alloc)
+        disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);
+    if (debugout) MESSAGE("D{");
+    for (i=0; i< disps->cArgs; i++) {
+        TYPEDESC vdesc;
+
+	vdesc.vt = VT_VARIANT;
+	hres = deserialize_param(
+	    tinfo,
+	    readit,
+	    debugout,
+	    alloc,
+	    &vdesc,
+	    (DWORD*)(disps->rgvarg+i),
+	    buf
+	);
     }
-    case VT_VOID:
-	/* Hacky. If we are LPVOID* we apparently have to guess the IID
-	 * for the interface. This sucks pretty badly. */
-	return _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg);
-    default:	ERR("Cannot unmarshal type %d\n",tdesc->vt);
-		return E_FAIL;
+    if (debugout) MESSAGE("}{");
+    hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));
+    if (hres)
+	return hres;
+    if (disps->cNamedArgs) {
+	if (alloc)
+	    disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);
+	for (i=0; i< disps->cNamedArgs; i++) {
+	    TYPEDESC vdesc;
+
+	    vdesc.vt = VT_UINT;
+	    hres = deserialize_param(
+		tinfo,
+		readit,
+		debugout,
+		alloc,
+		&vdesc,
+		(DWORD*)(disps->rgdispidNamedArgs+i),
+		buf
+	    );
+	    if (debugout && i<(disps->cNamedArgs-1)) MESSAGE(",");
+	}
     }
+    if (debugout) MESSAGE("}");
     return S_OK;
 }
 
 /* Searches function, also in inherited interfaces */
 static HRESULT
 _get_funcdesc(
-	ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc,
-	BSTR *iname, BSTR *fname
+    ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname
 ) {
     int i = 0, j = 0;
     HRESULT hres;
@@ -564,17 +1107,6 @@
     return E_FAIL;
 }
 
-/* how much space do we use on stack in DWORD steps. */
-static int
-_argsize(DWORD vt_type) {
-    switch (vt_type) {
-    case VT_VARIANT:
-	return (sizeof(VARIANT)+3)/sizeof(DWORD);
-    default:
-	return 1;
-    }
-}
-
 static DWORD
 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
     DWORD		*args = ((DWORD*)&tpinfo)+1, *xargs;
@@ -609,10 +1141,11 @@
     }
     /* Need them for hack below */
     memset(names,0,sizeof(names));
-    ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
-    if (nrofnames > sizeof(names)/sizeof(names[0])) {
+    if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
+	nrofnames = 0;
+    if (nrofnames > sizeof(names)/sizeof(names[0]))
 	ERR("Need more names!\n");
-    }
+
     memset(&buf,0,sizeof(buf));
     buf.iid = IID_IUnknown;
     if (method == 0) {
@@ -622,28 +1155,67 @@
 	xargs = args;
 	for (i=0;i<fdesc->cParams;i++) {
 	    ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	    BOOL	isserialized = FALSE;
 	    if (relaydeb) {
 		if (i) MESSAGE(",");
 		if (i+1<nrofnames && names[i+1])
 		    MESSAGE("%s=",debugstr_w(names[i+1]));
 	    }
-	    if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW)) {
-		buf.thisisiid = TRUE;
-	    } else {
-		buf.thisisiid = FALSE;
-	    }
 	    /* No need to marshal other data than FIN */
 	    if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
 		xargs+=_argsize(elem->tdesc.vt);
 		if (relaydeb) MESSAGE("[out]");
 		continue;
 	    }
-	    hres = marshall_param(tpinfo->tinfo,elem,NULL,xargs,&buf);
-	    xargs+=_argsize(elem->tdesc.vt);
+	    if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
+		/* If the parameter is 'riid', we use it as interface IID
+		 * for a later ppvObject serialization.
+		 */
+		buf.thisisiid = !lstrcmpW(names[i+1],riidW);
+
+		/* DISPPARAMS* needs special serializer */
+		if (!lstrcmpW(names[i+1],pdispparamsW)) {
+		    hres = serialize_DISPPARAM_ptr(
+			tpinfo->tinfo,
+			elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
+			relaydeb,
+			FALSE,
+			&elem->tdesc,
+			xargs,
+			&buf
+		    );
+		    isserialized = TRUE;
+		}
+		if (!lstrcmpW(names[i+1],ppvObjectW)) {
+		    hres = serialize_LPVOID_ptr(
+			tpinfo->tinfo,
+			elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
+			relaydeb,
+			FALSE,
+			&elem->tdesc,
+			xargs,
+			&buf
+		    );
+		    if (hres == S_OK)
+		        isserialized = TRUE;
+		}
+	    }
+	    if (!isserialized)
+		hres = serialize_param(
+		    tpinfo->tinfo,
+		    elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
+		    relaydeb,
+		    FALSE,
+		    &elem->tdesc,
+		    xargs,
+		    &buf
+		);
+
 	    if (hres) {
-		FIXME("Failed to marshall param, hres %lx\n",hres);
+		FIXME("Failed to serialize param, hres %lx\n",hres);
 		break;
 	    }
+	    xargs+=_argsize(elem->tdesc.vt);
 	}
     }
     if (relaydeb) MESSAGE(")");
@@ -656,11 +1228,13 @@
 	return hres;
     }
     memcpy(msg.Buffer,buf.base,buf.curoff);
+    if (relaydeb) MESSAGE("\n");
     hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
     if (hres) {
 	FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres);
 	return hres;
     }
+    relaydeb = TRACE_ON(olerelay);
     if (relaydeb) MESSAGE(" = %08lx (",status);
     if (buf.base)
 	buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
@@ -676,6 +1250,7 @@
 	xargs = args;
 	for (i=0;i<fdesc->cParams;i++) {
 	    ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	    BOOL	isdeserialized = FALSE;
 
 	    if (relaydeb) {
 		if (i) MESSAGE(",");
@@ -687,15 +1262,61 @@
 		if (relaydeb) MESSAGE("[in]");
 		continue;
 	    }
-	    hres = unmarshall_param(tpinfo->tinfo,elem,&(elem->tdesc),xargs,&buf);
-	    xargs += _argsize(elem->tdesc.vt);
+	    if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
+		/* If the parameter is 'riid', we use it as interface IID
+		 * for a later ppvObject serialization.
+		 */
+		buf.thisisiid = !lstrcmpW(names[i+1],riidW);
+
+		/* deserialize DISPPARAM */
+		if (!lstrcmpW(names[i+1],pdispparamsW)) {
+		    hres = deserialize_DISPPARAM_ptr(
+			tpinfo->tinfo,
+			elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+			relaydeb,
+			FALSE,
+			&(elem->tdesc),
+			xargs,
+			&buf
+		    );
+		    if (hres) {
+			FIXME("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
+			break;
+		    }
+		    isdeserialized = TRUE;
+		}
+		if (!lstrcmpW(names[i+1],ppvObjectW)) {
+		    hres = deserialize_LPVOID_ptr(
+			tpinfo->tinfo,
+			elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+			relaydeb,
+			FALSE,
+			&elem->tdesc,
+			xargs,
+			&buf
+		    );
+		    if (hres == S_OK)
+			isdeserialized = TRUE;
+		}
+	    }
+	    if (!isdeserialized)
+		hres = deserialize_param(
+		    tpinfo->tinfo,
+		    elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+		    relaydeb,
+		    FALSE,
+		    &(elem->tdesc),
+		    xargs,
+		    &buf
+		);
 	    if (hres) {
 		FIXME("Failed to unmarshall param, hres %lx\n",hres);
 		break;
 	    }
+	    xargs += _argsize(elem->tdesc.vt);
 	}
     }
-    if (relaydeb) MESSAGE(")\n");
+    if (relaydeb) MESSAGE(")\n\n");
     HeapFree(GetProcessHeap(),0,buf.base);
     return status;
 }
@@ -840,208 +1461,6 @@
     return;
 }
 
-static HRESULT
-stuballoc_param(
-    ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
-) {
-    HRESULT hres;
-
-    while (1) {
-	switch (tdesc->vt) {
-	case VT_VARIANT: {
-	    DWORD	vttype;
-	    VARIANT	*vt = (VARIANT*)arg;
-	    TYPEDESC	tdesc2;
-
-	    hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
-	    if (hres) return hres;
-	    memset(&tdesc2,0,sizeof(tdesc));
-	    tdesc2.vt = vttype;
-	    V_VT(vt)  = vttype;
-	    return stuballoc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf);
-	}
-	case VT_BOOL: case VT_I4:
-	    xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
-	    return S_OK;
-	case VT_BSTR: {
-		WCHAR	*str;
-		DWORD	len;
-
-		hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
-		if (hres)
-		    return hres;
-		str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
-		hres = xbuf_get(buf,(LPBYTE)str,len);
-		if (hres) return hres;
-		*arg = (DWORD)SysAllocStringLen(str,len);
-		HeapFree(GetProcessHeap(),0,str);
-		return S_OK;
-	    }
-	case VT_PTR:
-	    if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
-		(tdesc->u.lptdesc->vt != VT_VOID)
-	    ) {
-		*arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
-		arg = (DWORD*)*arg;
-	    }
-	    tdesc = tdesc->u.lptdesc;
-	    break;
-	case VT_UNKNOWN:
-	    /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
-	    *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
-	    hres = S_OK;
-	    if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)
-		hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
-	    return hres;
-	case VT_VOID:
-	    *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID));
-	    hres = S_OK;
-	    if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)
-		hres = _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg);
-	    return hres;
-	case VT_USERDEFINED: {
-	    if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) {
-		ITypeInfo	*tinfo2;
-		TYPEATTR	*tattr;
-
-		hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
-		if (hres) {
-		    FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
-		    return hres;
-		}
-		hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
-		if (hres) {
-		    FIXME("Could not get typeattr in VT_USERDEFINED.\n");
-		    return hres;
-		}
-		switch (tattr->typekind) {
-		case TKIND_INTERFACE:
-		    hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
-		    break;
-		case TKIND_RECORD:
-		    *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
-		    hres = xbuf_get(buf,(LPBYTE)*arg,tattr->cbSizeInstance);
-		    if (buf->thisisiid)
-			memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
-		    break;
-		default:
-		    FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
-		    hres = E_FAIL;
-		    break;
-		}
-		ITypeInfo_Release(tinfo2);
-		return hres;
-	    } else {
-		*arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID));
-		return S_OK;
-	    }
-	}
-	default:
-	    ERR("No handler for VT type %d, just allocating 4 bytes.\n",tdesc->vt);
-	    *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
-	    return S_OK;
-	}
-    }
-}
-
-static HRESULT
-stubunalloc_param(
-    ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
-) {
-    HRESULT hres = S_OK;
-
-    if (!tdesc) tdesc = &(elem->tdesc);
-
-    switch (tdesc->vt) {
-    case VT_BOOL:
-    case VT_I4:
-	hres = S_OK;
-	if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)
-	    hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
-	return hres;
-    case VT_VARIANT: {
-	TYPEDESC	tdesc2;
-	VARIANT		*vt = (VARIANT*)arg;
-	DWORD		vttype = V_VT(vt);
-
-	tdesc2.vt = vttype;
-	if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
-	    hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
-	    if (hres) return hres;
-	}
-	/* need to recurse since we need to free the stuff */
-	hres = stubunalloc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf);
-	return hres;
-    }
-    case VT_BSTR: {
-	if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
-	    DWORD *bstr = ((DWORD*)(*arg))-1;
-
-	    hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
-	    if (hres)
-		return hres;
-	}
-	SysFreeString((BSTR)*arg);
-	return S_OK;
-    }
-    case VT_PTR:
-	/*FIXME("VT_PTR *arg is %p\n",(LPVOID)*arg);*/
-	if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
-	    (tdesc->u.lptdesc->vt != VT_VOID)
-	) {
-	    hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,arg,buf);
-	} else {
-	    hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf);
-	    HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
-	}
-	return hres;
-    case VT_UNKNOWN:
-	if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
-	    FIXME("Marshaling back VT_UNKNOWN %lx\n",*arg);
-	    hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
-	}
-	HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
-	return hres;
-    case VT_VOID:
-	hres = S_OK;
-	if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)
-	    hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)*arg);
-	return hres;
-    case VT_USERDEFINED: {
-	ITypeInfo	*tinfo2;
-	TYPEATTR	*tattr;
-
-	if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
-	    /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/
-	    hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
-	    if (hres) {
-		FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
-		return hres;
-	    }
-	    ITypeInfo_GetTypeAttr(tinfo2,&tattr);
-	    switch (tattr->typekind) {
-	    case TKIND_INTERFACE:
-		hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)*arg);
-		break;
-	    case TKIND_RECORD:
-		hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance);
-		break;
-	    default:
-		FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
-		hres = E_FAIL;
-		break;
-	    }
-	    ITypeInfo_Release(tinfo2);
-	}
-	return hres;
-    }
-    default:
-	ERR("Unhandled marshal type %d.\n",tdesc->vt);
-	HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
-	return S_OK;
-    }
-}
-
 static HRESULT WINAPI
 TMStubImpl_Invoke(
     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf
@@ -1096,15 +1515,58 @@
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
 	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	BOOL		isdeserialized = FALSE;
 
-	if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW))
-	    buf.thisisiid = TRUE;
-	else
-	    buf.thisisiid = FALSE;
-	hres   = stuballoc_param(This->tinfo,elem,&(elem->tdesc),xargs,&buf);
+	if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
+	    /* If the parameter is 'riid', we use it as interface IID
+	     * for a later ppvObject serialization.
+	     */
+	    buf.thisisiid = !lstrcmpW(names[i+1],riidW);
+
+	    /* deserialize DISPPARAM */
+	    if (!lstrcmpW(names[i+1],pdispparamsW)) {
+		hres = deserialize_DISPPARAM_ptr(
+		    This->tinfo,
+		    elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
+		    FALSE,
+		    TRUE,
+		    &(elem->tdesc),
+		    xargs,
+		    &buf
+		);
+		if (hres) {
+		    FIXME("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
+		    break;
+		}
+		isdeserialized = TRUE;
+	    }
+	    if (!lstrcmpW(names[i+1],ppvObjectW)) {
+		hres = deserialize_LPVOID_ptr(
+		    This->tinfo,
+		    elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+		    FALSE,
+		    TRUE,
+		    &elem->tdesc,
+		    xargs,
+		    &buf
+		);
+		if (hres == S_OK)
+		    isdeserialized = TRUE;
+	    }
+	}
+	if (!isdeserialized)
+	    hres = deserialize_param(
+		This->tinfo,
+		elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
+		FALSE,
+		TRUE,
+		&(elem->tdesc),
+		xargs,
+		&buf
+	    );
 	xargs += _argsize(elem->tdesc.vt);
 	if (hres) {
-	    FIXME("Failed to stuballoc param %s, hres %lx\n",debugstr_w(names[i+1]),hres);
+	    FIXME("Failed to deserialize param %s, hres %lx\n",debugstr_w(names[i+1]),hres);
 	    break;
 	}
     }
@@ -1124,7 +1586,51 @@
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
 	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
-	hres = stubunalloc_param(This->tinfo,elem,NULL,xargs,&buf);
+	BOOL		isserialized = FALSE;
+
+	if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
+	    /* If the parameter is 'riid', we use it as interface IID
+	     * for a later ppvObject serialization.
+	     */
+	    buf.thisisiid = !lstrcmpW(names[i+1],riidW);
+
+	    /* DISPPARAMS* needs special serializer */
+	    if (!lstrcmpW(names[i+1],pdispparamsW)) {
+		hres = serialize_DISPPARAM_ptr(
+		    This->tinfo,
+		    elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+		    FALSE,
+		    TRUE,
+		    &elem->tdesc,
+		    xargs,
+		    &buf
+		);
+		isserialized = TRUE;
+	    }
+	    if (!lstrcmpW(names[i+1],ppvObjectW)) {
+		hres = serialize_LPVOID_ptr(
+		    This->tinfo,
+		    elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+		    FALSE,
+		    TRUE,
+		    &elem->tdesc,
+		    xargs,
+		    &buf
+		);
+		if (hres == S_OK)
+		    isserialized = TRUE;
+	    }
+	}
+	if (!isserialized)
+	    hres = serialize_param(
+	       This->tinfo,
+	       elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+	       FALSE,
+	       TRUE,
+	       &elem->tdesc,
+	       xargs,
+	       &buf
+	    );
 	xargs += _argsize(elem->tdesc.vt);
 	if (hres) {
 	    FIXME("Failed to stuballoc param, hres %lx\n",hres);