Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / oleaut32 / tmarshal.c
index 4dc5a66..50a9135 100644 (file)
@@ -1,7 +1,10 @@
 /*
  *     TYPELIB Marshaler
  *
- *     Copyright 2002  Marcus Meissner
+ *     Copyright 2002,2005     Marcus Meissner
+ *
+ * The olerelay debug channel allows you to see calls marshalled by
+ * the typelib marshaller. It is not a generic COM relaying system.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdio.h>
 #include <ctype.h>
 
+#define COBJMACROS
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
+
 #include "winerror.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
 
 #include "ole2.h"
-#include "wine/unicode.h"
-#include "ole2disp.h"
 #include "typelib.h"
 #include "wine/debug.h"
-#include "winternl.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};
+static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
 
+#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
+
 typedef struct _marshal_state {
     LPBYTE     base;
     int                size;
     int                curoff;
-
-    BOOL       thisisiid;
-    IID                iid;    /* HACK: for VT_VOID */
 } marshal_state;
 
+/* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
+static char *relaystr(WCHAR *in) {
+    char *tmp = (char *)debugstr_w(in);
+    tmp += 2;
+    tmp[strlen(tmp)-1] = '\0';
+    return tmp;
+}
+
 static HRESULT
 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
     while (buf->size - buf->curoff < size) {
@@ -104,34 +111,49 @@ _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
     DWORD              xsize;
 
     TRACE("...%s...\n",debugstr_guid(riid));
+    
     *pUnk = NULL;
     hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
-    if (hres) return hres;
+    if (hres) {
+        ERR("xbuf_get failed\n");
+        return hres;
+    }
+    
     if (xsize == 0) return S_OK;
+    
     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
     if (hres) {
-       FIXME("Stream create failed %lx\n",hres);
+       ERR("Stream create failed %lx\n",hres);
        return hres;
     }
+    
     hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
-    if (hres) { FIXME("stream write %lx\n",hres); return hres; }
+    if (hres) {
+        ERR("stream write %lx\n",hres);
+        return hres;
+    }
+    
     memset(&seekto,0,sizeof(seekto));
     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
-    if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;}
+    if (hres) {
+        ERR("Failed Seek %lx\n",hres);
+        return hres;
+    }
+    
     hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
     if (hres) {
-       FIXME("Marshalling interface %s failed with %lx\n",debugstr_guid(riid),hres);
+       ERR("Unmarshalling interface %s failed with %lx\n",debugstr_guid(riid),hres);
        return hres;
     }
+    
     IStream_Release(pStm);
     return xbuf_skip(buf,xsize);
 }
 
 static HRESULT
 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
-    LPUNKNOWN          newiface;
-    LPBYTE             tempbuf;
-    IStream            *pStm;
+    LPBYTE             tempbuf = NULL;
+    IStream            *pStm = NULL;
     STATSTG            ststg;
     ULARGE_INTEGER     newpos;
     LARGE_INTEGER      seekto;
@@ -139,45 +161,67 @@ _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
     DWORD              xsize;
     HRESULT            hres;
 
-    hres = S_OK;
-    if (!pUnk)
-       goto fail;
+    if (!pUnk) {
+       /* this is valid, if for instance we serialize
+        * a VT_DISPATCH with NULL ptr which apparently
+        * can happen. S_OK to make sure we continue
+        * serializing.
+        */
+        ERR("pUnk is NULL?\n");
+        xsize = 0;
+        return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
+    }
+
+    hres = E_FAIL;
 
     TRACE("...%s...\n",debugstr_guid(riid));
-    hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
-    if (hres) {
-       TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
-       goto fail;
-    }
+    
     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
     if (hres) {
-       FIXME("Stream create failed %lx\n",hres);
+       ERR("Stream create failed %lx\n",hres);
        goto fail;
     }
-    hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
-    IUnknown_Release(newiface);
+    
+    hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
     if (hres) {
-       FIXME("Marshalling interface %s failed with %lx\n",
-               debugstr_guid(riid),hres
-       );
+       ERR("Marshalling interface %s failed with %lx\n", debugstr_guid(riid), hres);
        goto fail;
     }
+    
     hres = IStream_Stat(pStm,&ststg,0);
+    if (hres) {
+        ERR("Stream stat failed\n");
+        goto fail;
+    }
+    
     tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
     memset(&seekto,0,sizeof(seekto));
     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
-    if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;}
+    if (hres) {
+        ERR("Failed Seek %lx\n",hres);
+        goto fail;
+    }
+    
     hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
-    if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;}
-    IStream_Release(pStm);
+    if (hres) {
+        ERR("Failed Read %lx\n",hres);
+        goto fail;
+    }
+    
     xsize = ststg.cbSize.u.LowPart;
     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
     hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
+    
     HeapFree(GetProcessHeap(),0,tempbuf);
+    IStream_Release(pStm);
+    
     return hres;
+    
 fail:
     xsize = 0;
     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
+    if (pStm) IUnknown_Release(pStm);
+    HeapFree(GetProcessHeap(), 0, tempbuf);
     return hres;
 }
 
@@ -203,7 +247,8 @@ _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
     char       tlguid[200],typelibkey[300],interfacekey[300],ver[100];
     char       tlfn[260];
     OLECHAR    tlfnW[260];
-    DWORD      tlguidlen, verlen, type, tlfnlen;
+    DWORD      tlguidlen, verlen, type;
+    LONG       tlfnlen;
     ITypeLib   *tl;
 
     sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
@@ -213,20 +258,20 @@ _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
     );
 
     if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
-       FIXME("No %s key found.\n",interfacekey);
+       ERR("No %s key found.\n",interfacekey);
                return E_FAIL;
     }
     type = (1<<REG_SZ);
     tlguidlen = sizeof(tlguid);
-    if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
-       FIXME("Getting typelib guid failed.\n");
+    if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
+       ERR("Getting typelib guid failed.\n");
        RegCloseKey(ikey);
        return E_FAIL;
     }
     type = (1<<REG_SZ);
     verlen = sizeof(ver);
-    if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
-       FIXME("Could not get version value?\n");
+    if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
+       ERR("Could not get version value?\n");
        RegCloseKey(ikey);
        return E_FAIL;
     }
@@ -234,7 +279,7 @@ _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
     sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
     tlfnlen = sizeof(tlfn);
     if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
-       FIXME("Could not get typelib fn?\n");
+       ERR("Could not get typelib fn?\n");
        return E_FAIL;
     }
     MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
@@ -259,12 +304,12 @@ _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
  */
 static int _nroffuncs(ITypeInfo *tinfo) {
     int        n, max = 0;
-    FUNCDESC   *fdesc;
+    const FUNCDESC *fdesc;
     HRESULT    hres;
 
     n=0;
     while (1) {
-       hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
+       hres = ITypeInfoImpl_GetInternalFuncDesc(tinfo,n,&fdesc);
        if (hres)
            return max+1;
        if (fdesc->oVft/4 > max)
@@ -274,6 +319,8 @@ static int _nroffuncs(ITypeInfo *tinfo) {
     /*NOTREACHED*/
 }
 
+#ifdef __i386__
+
 #include "pshpack1.h"
 
 typedef struct _TMAsmProxy {
@@ -289,74 +336,104 @@ typedef struct _TMAsmProxy {
 
 #include "poppack.h"
 
+#else /* __i386__ */
+# warning You need to implement stubless proxies for your architecture
+typedef struct _TMAsmProxy {
+} TMAsmProxy;
+#endif
+
 typedef struct _TMProxyImpl {
-    DWORD                              *lpvtbl;
-    ICOM_VTABLE(IRpcProxyBuffer)       *lpvtbl2;
-    DWORD                              ref;
+    LPVOID                             *lpvtbl;
+    const IRpcProxyBufferVtbl          *lpvtbl2;
+    LONG                               ref;
 
     TMAsmProxy                         *asmstubs;
     ITypeInfo*                         tinfo;
     IRpcChannelBuffer*                 chanbuf;
     IID                                        iid;
+    CRITICAL_SECTION   crit;
+    IUnknown                           *outerunknown;
+    IDispatch                          *dispatch;
 } TMProxyImpl;
 
 static HRESULT WINAPI
-TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) {
+TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
+{
     TRACE("()\n");
     if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
-       *ppv = (LPVOID)iface;
-       IRpcProxyBuffer_AddRef(iface);
-       return S_OK;
+        *ppv = (LPVOID)iface;
+        IRpcProxyBuffer_AddRef(iface);
+        return S_OK;
     }
     FIXME("no interface for %s\n",debugstr_guid(riid));
     return E_NOINTERFACE;
 }
 
 static ULONG WINAPI
-TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) {
+TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
+{
     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
+    ULONG refCount = InterlockedIncrement(&This->ref);
 
-    TRACE("()\n");
-    This->ref++;
-    return This->ref;
+    TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);
+
+    return refCount;
 }
 
 static ULONG WINAPI
-TMProxyImpl_Release(LPRPCPROXYBUFFER iface) {
+TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
+{
     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
+    ULONG refCount = InterlockedDecrement(&This->ref);
 
-    TRACE("()\n");
-    This->ref--;
-    if (This->ref) return This->ref;
-    if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
-    HeapFree(GetProcessHeap(),0,This);
-    return 0;
+    TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1);
+
+    if (!refCount)
+    {
+        if (This->dispatch) IDispatch_Release(This->dispatch);
+        DeleteCriticalSection(&This->crit);
+        if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
+        VirtualFree(This->asmstubs, 0, MEM_RELEASE);
+        CoTaskMemFree(This);
+    }
+    return refCount;
 }
 
 static HRESULT WINAPI
 TMProxyImpl_Connect(
-    LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer
-) {
-    ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
+    LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
+{
+    ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
+
+    TRACE("(%p)\n", pRpcChannelBuffer);
 
-    TRACE("(%p)\n",pRpcChannelBuffer);
+    EnterCriticalSection(&This->crit);
+
+    IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
     This->chanbuf = pRpcChannelBuffer;
-    IRpcChannelBuffer_AddRef(This->chanbuf);
+
+    LeaveCriticalSection(&This->crit);
+
     return S_OK;
 }
 
 static void WINAPI
-TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) {
-    ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
+TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
+{
+    ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
+
+    TRACE("()\n");
+
+    EnterCriticalSection(&This->crit);
 
-    FIXME("()\n");
     IRpcChannelBuffer_Release(This->chanbuf);
     This->chanbuf = NULL;
+
+    LeaveCriticalSection(&This->crit);
 }
 
 
-static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+static const IRpcProxyBufferVtbl tmproxyvtable = {
     TMProxyImpl_QueryInterface,
     TMProxyImpl_AddRef,
     TMProxyImpl_Release,
@@ -365,9 +442,15 @@ static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = {
 };
 
 /* how much space do we use on stack in DWORD steps. */
-int const
+int
 _argsize(DWORD vt) {
     switch (vt) {
+    case VT_UI8:
+       return 8/sizeof(DWORD);
+    case VT_R8:
+        return sizeof(double)/sizeof(DWORD);
+    case VT_CY:
+        return sizeof(CY)/sizeof(DWORD);
     case VT_DATE:
        return sizeof(DATE)/sizeof(DWORD);
     case VT_VARIANT:
@@ -392,6 +475,9 @@ _xsize(TYPEDESC *td) {
            arrsize *= adesc->rgbounds[i].cElements;
        return arrsize*_xsize(&adesc->tdescElem);
     }
+    case VT_UI8:
+    case VT_I8:
+       return 8;
     case VT_UI2:
     case VT_I2:
        return 2;
@@ -411,8 +497,8 @@ serialize_param(
     BOOL               dealloc,
     TYPEDESC           *tdesc,
     DWORD              *arg,
-    marshal_state      *buf
-{
+    marshal_state      *buf)
+{
     HRESULT hres = S_OK;
 
     TRACE("(tdesc.vt %d)\n",tdesc->vt);
@@ -420,54 +506,108 @@ serialize_param(
     switch (tdesc->vt) {
     case VT_EMPTY: /* nothing. empty variant for instance */
        return S_OK;
+    case VT_I8:
+    case VT_UI8:
+       hres = S_OK;
+       if (debugout) TRACE_(olerelay)("%lx%lx",arg[0],arg[1]);
+       if (writeit)
+           hres = xbuf_add(buf,(LPBYTE)arg,8);
+       return hres;
     case VT_BOOL:
     case VT_ERROR:
-    case VT_UI4:
     case VT_UINT:
     case VT_I4:
     case VT_R4:
+    case VT_UI4:
+       hres = S_OK;
+       if (debugout) TRACE_(olerelay)("%lx",*arg);
+       if (writeit)
+           hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
+       return hres;
+    case VT_I2:
     case VT_UI2:
+       hres = S_OK;
+       if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff);
+       if (writeit)
+           hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
+       return hres;
+    case VT_I1:
     case VT_UI1:
        hres = S_OK;
-       if (debugout) MESSAGE("%lx",*arg);
+       if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff);
        if (writeit)
            hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
        return hres;
+    case VT_I4|VT_BYREF:
+       hres = S_OK;
+       if (debugout) TRACE_(olerelay)("&0x%lx",*arg);
+       if (writeit)
+           hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD));
+       /* do not dealloc at this time */
+       return hres;
     case VT_VARIANT: {
        TYPEDESC        tdesc2;
        VARIANT         *vt = (VARIANT*)arg;
        DWORD           vttype = V_VT(vt);
 
-       if (debugout) MESSAGE("Vt(%ld)(",vttype);
+       if (debugout) TRACE_(olerelay)("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(")");
+       hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,(DWORD*)&(V_I4(vt)),buf);
+       if (debugout) TRACE_(olerelay)(")");
        return hres;
     }
+    case VT_BSTR|VT_BYREF: {
+       if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : "<bstr NULL>");
+        if (writeit) {
+            /* ptr to ptr to magic widestring, basically */
+            BSTR *bstr = (BSTR *) *arg;
+            DWORD len;
+            if (!*bstr) {
+                /* -1 means "null string" which is equivalent to empty string */
+                len = -1;     
+                hres = xbuf_add(buf, (LPBYTE)&len,sizeof(DWORD));
+               if (hres) return hres;
+            } else {
+               len = *((DWORD*)*bstr-1)/sizeof(WCHAR);
+               hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
+               if (hres) return hres;
+               hres = xbuf_add(buf,(LPBYTE)*bstr,len * sizeof(WCHAR));
+               if (hres) return hres;
+            }
+        }
+
+        if (dealloc && arg) {
+            BSTR *str = *((BSTR **)arg);
+            SysFreeString(*str);
+        }
+        return S_OK;
+    }
+    
     case VT_BSTR: {
        if (debugout) {
-           if (arg)
-                   MESSAGE("%s",debugstr_w((BSTR)*arg));
+           if (*arg)
+                   TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
            else
-                   MESSAGE("<bstr NULL>");
+                   TRACE_(olerelay)("<bstr NULL>");
        }
        if (writeit) {
-           if (!*arg) {
-               DWORD fakelen = -1;
-               hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
-               if (hres)
-                   return hres;
+            BSTR bstr = (BSTR)*arg;
+            DWORD len;
+           if (!bstr) {
+               len = -1;
+               hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
+               if (hres) return hres;
            } else {
-               DWORD *bstr = ((DWORD*)(*arg))-1;
-
-               hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
-               if (hres)
-                   return hres;
+               len = *((DWORD*)bstr-1)/sizeof(WCHAR);
+               hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
+               if (hres) return hres;
+               hres = xbuf_add(buf,(LPBYTE)bstr,len * sizeof(WCHAR));
+               if (hres) return hres;
            }
        }
 
@@ -477,34 +617,63 @@ serialize_param(
     }
     case VT_PTR: {
        DWORD cookie;
+       BOOL        derefhere = TRUE;
 
-       if (debugout) MESSAGE("*");
-       if (writeit) {
-           cookie = *arg ? 0x42424242 : 0;
-           hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
-           if (hres)
+       if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
+           ITypeInfo   *tinfo2;
+           TYPEATTR    *tattr;
+
+           hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
+           if (hres) {
+               ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
                return hres;
+           }
+           ITypeInfo_GetTypeAttr(tinfo2,&tattr);
+           switch (tattr->typekind) {
+           case TKIND_ENUM:    /* confirmed */
+           case TKIND_RECORD:  /* FIXME: mostly untested */
+               derefhere=TRUE;
+               break;
+           case TKIND_ALIAS:   /* FIXME: untested */
+           case TKIND_DISPATCH:        /* will be done in VT_USERDEFINED case */
+           case TKIND_INTERFACE:       /* will be done in VT_USERDEFINED case */
+               derefhere=FALSE;
+               break;
+           default:
+               FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
+               derefhere=FALSE;
+               break;
+           }
+           ITypeInfo_Release(tinfo2);
        }
+
+       if (debugout) TRACE_(olerelay)("*");
+       /* Write always, so the other side knows when it gets a NULL pointer.
+        */
+       cookie = *arg ? 0x42424242 : 0;
+       hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
+       if (hres)
+           return hres;
        if (!*arg) {
-           if (debugout) MESSAGE("NULL");
+           if (debugout) TRACE_(olerelay)("NULL");
            return S_OK;
        }
        hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
-       if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
+       if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
        return hres;
     }
     case VT_UNKNOWN:
-       if (debugout) MESSAGE("unk(0x%lx)",*arg);
+       if (debugout) TRACE_(olerelay)("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 (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg);
        if (writeit)
            hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
        return hres;
     case VT_VOID:
-       if (debugout) MESSAGE("<void>");
+       if (debugout) TRACE_(olerelay)("<void>");
        return S_OK;
     case VT_USERDEFINED: {
        ITypeInfo       *tinfo2;
@@ -512,7 +681,7 @@ serialize_param(
 
        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);
+           ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
            return hres;
        }
        ITypeInfo_GetTypeAttr(tinfo2,&tattr);
@@ -521,10 +690,12 @@ serialize_param(
        case TKIND_INTERFACE:
            if (writeit)
               hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
+           if (dealloc)
+               IUnknown_Release((LPUNKNOWN)arg);
            break;
        case TKIND_RECORD: {
            int i;
-           if (debugout) MESSAGE("{");
+           if (debugout) TRACE_(olerelay)("{");
            for (i=0;i<tattr->cVars;i++) {
                VARDESC *vdesc;
                ELEMDESC *elem2;
@@ -532,7 +703,7 @@ serialize_param(
 
                hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
                if (hres) {
-                   FIXME("Could not get vardesc of %d\n",i);
+                   ERR("Could not get vardesc of %d\n",i);
                    return hres;
                }
                /* Need them for hack below */
@@ -543,7 +714,7 @@ serialize_param(
                    ERR("Need more names!\n");
                }
                if (!hres && debugout)
-                   MESSAGE("%s=",debugstr_w(names[0]));
+                   TRACE_(olerelay)("%s=",relaystr(names[0]));
                */
                elem2 = &vdesc->elemdescVar;
                tdesc2 = &elem2->tdesc;
@@ -556,16 +727,23 @@ serialize_param(
                    (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
                    buf
                );
+                ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
                if (hres!=S_OK)
                    return hres;
                if (debugout && (i<(tattr->cVars-1)))
-                   MESSAGE(",");
+                   TRACE_(olerelay)(",");
            }
-           if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
-               memcpy(&(buf->iid),arg,sizeof(buf->iid));
-           if (debugout) MESSAGE("}");
+           if (debugout) TRACE_(olerelay)("}");
            break;
        }
+       case TKIND_ALIAS:
+           return serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
+       case TKIND_ENUM:
+           hres = S_OK;
+           if (debugout) TRACE_(olerelay)("%lx",*arg);
+           if (writeit)
+               hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
+           return hres;
        default:
            FIXME("Unhandled typekind %d\n",tattr->typekind);
            hres = E_FAIL;
@@ -578,19 +756,20 @@ serialize_param(
        ARRAYDESC *adesc = tdesc->u.lpadesc;
        int i, arrsize = 1;
 
-       if (debugout) MESSAGE("carr");
+       if (debugout) TRACE_(olerelay)("carr");
        for (i=0;i<adesc->cDims;i++) {
-           if (debugout) MESSAGE("[%ld]",adesc->rgbounds[i].cElements);
+           if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);
            arrsize *= adesc->rgbounds[i].cElements;
        }
-       if (debugout) MESSAGE("[");
+       if (debugout) TRACE_(olerelay)("(vt %d)",adesc->tdescElem.vt);
+       if (debugout) TRACE_(olerelay)("[");
        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 && (i<arrsize-1)) TRACE_(olerelay)(",");
        }
-       if (debugout) MESSAGE("]");
+       if (debugout) TRACE_(olerelay)("]");
        return S_OK;
     }
     default:
@@ -599,133 +778,6 @@ serialize_param(
     }
 }
 
-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
 deserialize_param(
     ITypeInfo          *tinfo,
@@ -734,8 +786,8 @@ deserialize_param(
     BOOL               alloc,
     TYPEDESC           *tdesc,
     DWORD              *arg,
-    marshal_state      *buf
-{
+    marshal_state      *buf)
+{
     HRESULT hres = S_OK;
 
     TRACE("vt %d at %p\n",tdesc->vt,arg);
@@ -743,10 +795,10 @@ deserialize_param(
     while (1) {
        switch (tdesc->vt) {
        case VT_EMPTY:
-           if (debugout) MESSAGE("<empty>");
+           if (debugout) TRACE_(olerelay)("<empty>");
            return S_OK;
        case VT_NULL:
-           if (debugout) MESSAGE("<null>");
+           if (debugout) TRACE_(olerelay)("<null>");
            return S_OK;
        case VT_VARIANT: {
            VARIANT     *vt = (VARIANT*)arg;
@@ -762,25 +814,97 @@ deserialize_param(
                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(")");
+               if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
+               hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, (DWORD*)&(V_I4(vt)), buf);
+               TRACE_(olerelay)(")");
                return hres;
            } else {
                VariantInit(vt);
                return S_OK;
            }
        }
+        case VT_I8:
+        case VT_UI8:
+           if (readit) {
+               hres = xbuf_get(buf,(LPBYTE)arg,8);
+               if (hres) ERR("Failed to read integer 8 byte\n");
+           }
+           if (debugout) TRACE_(olerelay)("%lx%lx",arg[0],arg[1]);
+           return hres;
         case VT_ERROR:
-       case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT: case VT_R4:
+       case VT_BOOL:
+        case VT_I4:
+        case VT_UINT:
+        case VT_R4:
+        case VT_UI4:
+           if (readit) {
+               hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
+               if (hres) ERR("Failed to read integer 4 byte\n");
+           }
+           if (debugout) TRACE_(olerelay)("%lx",*arg);
+           return hres;
+        case VT_I2:
         case VT_UI2:
+           if (readit) {
+               DWORD x;
+               hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
+               if (hres) ERR("Failed to read integer 4 byte\n");
+               memcpy(arg,&x,2);
+           }
+           if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff);
+           return hres;
+        case VT_I1:
        case VT_UI1:
            if (readit) {
-               hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
-               if (hres) FIXME("Failed to read integer 4 byte\n");
+               DWORD x;
+               hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
+               if (hres) ERR("Failed to read integer 4 byte\n");
+               memcpy(arg,&x,1);
+           }
+           if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff);
+           return hres;
+        case VT_I4|VT_BYREF:
+           hres = S_OK;
+           if (alloc)
+               *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
+           if (readit) {
+               hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD));
+               if (hres) ERR("Failed to read integer 4 byte\n");
            }
-           if (debugout) MESSAGE("%lx",*arg);
+           if (debugout) TRACE_(olerelay)("&0x%lx",*(DWORD*)*arg);
            return hres;
+       case VT_BSTR|VT_BYREF: {
+           BSTR **bstr = (BSTR **)arg;
+           WCHAR       *str;
+           DWORD       len;
+
+           if (readit) {
+               hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
+               if (hres) {
+                   ERR("failed to read bstr klen\n");
+                   return hres;
+               }
+               if (len == -1) {
+                    *bstr = CoTaskMemAlloc(sizeof(BSTR *));
+                   **bstr = NULL;
+                   if (debugout) TRACE_(olerelay)("<bstr NULL>");
+               } else {
+                   str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR));
+                   hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR));
+                   if (hres) {
+                       ERR("Failed to read BSTR.\n");
+                       return hres;
+                   }
+                    *bstr = CoTaskMemAlloc(sizeof(BSTR *));
+                   **bstr = SysAllocStringLen(str,len);
+                   if (debugout) TRACE_(olerelay)("%s",relaystr(str));
+                   HeapFree(GetProcessHeap(),0,str);
+               }
+           } else {
+               *bstr = NULL;
+           }
+           return S_OK;
+       }
        case VT_BSTR: {
            WCHAR       *str;
            DWORD       len;
@@ -788,21 +912,21 @@ deserialize_param(
            if (readit) {
                hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
                if (hres) {
-                   FIXME("failed to read bstr klen\n");
+                   ERR("failed to read bstr klen\n");
                    return hres;
                }
                if (len == -1) {
                    *arg = 0;
-                   if (debugout) MESSAGE("<bstr NULL>");
+                   if (debugout) TRACE_(olerelay)("<bstr NULL>");
                } else {
-                   str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
-                   hres = xbuf_get(buf,(LPBYTE)str,len);
+                   str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR));
+                   hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR));
                    if (hres) {
-                       FIXME("Failed to read BSTR.\n");
+                       ERR("Failed to read BSTR.\n");
                        return hres;
                    }
                    *arg = (DWORD)SysAllocStringLen(str,len);
-                   if (debugout) MESSAGE("%s",debugstr_w(str));
+                   if (debugout) TRACE_(olerelay)("%s",relaystr(str));
                    HeapFree(GetProcessHeap(),0,str);
                }
            } else {
@@ -812,24 +936,52 @@ deserialize_param(
        }
        case VT_PTR: {
            DWORD       cookie;
-           BOOL        derefhere = 0;
+           BOOL        derefhere = TRUE;
 
-           derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
+           if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
+               ITypeInfo       *tinfo2;
+               TYPEATTR        *tattr;
 
-           if (readit) {
-               hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
+               hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
                if (hres) {
-                   FIXME("Failed to load pointer cookie.\n");
+                   ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
                    return hres;
                }
-               if (cookie != 0x42424242) {
-                   if (debugout) MESSAGE("NULL");
-                   *arg = 0;
-                   return S_OK;
+               ITypeInfo_GetTypeAttr(tinfo2,&tattr);
+               switch (tattr->typekind) {
+               case TKIND_ENUM:        /* confirmed */
+               case TKIND_RECORD:      /* FIXME: mostly untested */
+                   derefhere=TRUE;
+                   break;
+               case TKIND_ALIAS:       /* FIXME: untested */
+               case TKIND_DISPATCH:    /* will be done in VT_USERDEFINED case */
+               case TKIND_INTERFACE:   /* will be done in VT_USERDEFINED case */
+                   derefhere=FALSE;
+                   break;
+               default:
+                   FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
+                   derefhere=FALSE;
+                   break;
                }
-               if (debugout) MESSAGE("*");
+               ITypeInfo_Release(tinfo2);
+           }
+           /* read it in all cases, we need to know if we have 
+            * NULL pointer or not.
+            */
+           hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
+           if (hres) {
+               ERR("Failed to load pointer cookie.\n");
+               return hres;
+           }
+           if (cookie != 0x42424242) {
+               /* we read a NULL ptr from the remote side */
+               if (debugout) TRACE_(olerelay)("NULL");
+               *arg = 0;
+               return S_OK;
            }
+           if (debugout) TRACE_(olerelay)("*");
            if (alloc) {
+               /* Allocate space for the referenced struct */
                if (derefhere)
                    *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
            }
@@ -846,17 +998,17 @@ deserialize_param(
            if (readit)
                hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
            if (debugout)
-               MESSAGE("unk(%p)",arg);
+               TRACE_(olerelay)("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);
+               TRACE_(olerelay)("idisp(%p)",arg);
            return hres;
        case VT_VOID:
-           if (debugout) MESSAGE("<void>");
+           if (debugout) TRACE_(olerelay)("<void>");
            return S_OK;
        case VT_USERDEFINED: {
            ITypeInfo   *tinfo2;
@@ -864,15 +1016,13 @@ deserialize_param(
 
            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);
+               ERR("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");
+               ERR("Could not get typeattr in VT_USERDEFINED.\n");
            } else {
-               if (alloc)
-                   *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
                switch (tattr->typekind) {
                case TKIND_DISPATCH:
                case TKIND_INTERFACE:
@@ -882,13 +1032,16 @@ deserialize_param(
                case TKIND_RECORD: {
                    int i;
 
-                   if (debugout) MESSAGE("{");
+                   if (alloc)
+                       *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,tattr->cbSizeInstance);
+
+                   if (debugout) TRACE_(olerelay)("{");
                    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);
+                           ERR("Could not get vardesc of %d\n",i);
                            return hres;
                        }
                        hres = deserialize_param(
@@ -900,13 +1053,21 @@ deserialize_param(
                            (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
                            buf
                        );
-                       if (debugout && (i<tattr->cVars-1)) MESSAGE(",");
+                        ITypeInfo2_ReleaseVarDesc(tinfo2, vdesc);
+                       if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
                    }
-                   if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
-                       memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
-                   if (debugout) MESSAGE("}");
+                   if (debugout) TRACE_(olerelay)("}");
                    break;
                }
+               case TKIND_ALIAS:
+                   return deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
+               case TKIND_ENUM:
+                   if (readit) {
+                       hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
+                       if (hres) ERR("Failed to read enum (4 byte)\n");
+                   }
+                   if (debugout) TRACE_(olerelay)("%lx",*arg);
+                   return hres;
                default:
                    ERR("Unhandled typekind %d\n",tattr->typekind);
                    hres = E_FAIL;
@@ -914,7 +1075,7 @@ deserialize_param(
                }
            }
            if (hres)
-               FIXME("failed to stuballoc in TKIND_RECORD.\n");
+               ERR("failed to stuballoc in TKIND_RECORD.\n");
            ITypeInfo_Release(tinfo2);
            return hres;
        }
@@ -945,141 +1106,23 @@ deserialize_param(
     }
 }
 
-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
-       );
-    }
-    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, ITypeInfo **tactual, const FUNCDESC **fdesc, BSTR *iname, BSTR *fname)
+{
     int i = 0, j = 0;
     HRESULT hres;
 
     if (fname) *fname = NULL;
     if (iname) *iname = NULL;
 
+    *tactual = tinfo;
+    ITypeInfo_AddRef(*tactual);
+
     while (1) {
-       hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
+       hres = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i, fdesc);
+
        if (hres) {
            ITypeInfo   *tinfo2;
            HREFTYPE    href;
@@ -1087,26 +1130,26 @@ _get_funcdesc(
 
            hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
            if (hres) {
-               FIXME("GetTypeAttr failed with %lx\n",hres);
+               ERR("GetTypeAttr failed with %lx\n",hres);
                return hres;
            }
            /* Not found, so look in inherited ifaces. */
            for (j=0;j<attr->cImplTypes;j++) {
                hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
                if (hres) {
-                   FIXME("Did not find a reftype for interface offset %d?\n",j);
+                   ERR("Did not find a reftype for interface offset %d?\n",j);
                    break;
                }
                hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
                if (hres) {
-                   FIXME("Did not find a typeinfo for reftype %ld?\n",href);
+                   ERR("Did not find a typeinfo for reftype %ld?\n",href);
                    continue;
                }
-               hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
+               hres = _get_funcdesc(tinfo2,iMethod,tactual,fdesc,iname,fname);
                ITypeInfo_Release(tinfo2);
                if (!hres) return S_OK;
            }
-           return E_FAIL;
+           return hres;
        }
        if (((*fdesc)->oVft/4) == iMethod) {
            if (fname)
@@ -1117,13 +1160,13 @@ _get_funcdesc(
        }
        i++;
     }
-    return E_FAIL;
 }
 
 static DWORD
-xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
+xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
+{
     DWORD              *args = ((DWORD*)&tpinfo)+1, *xargs;
-    FUNCDESC           *fdesc;
+    const FUNCDESC     *fdesc;
     HRESULT            hres;
     int                        i, relaydeb = TRACE_ON(olerelay);
     marshal_state      buf;
@@ -1131,124 +1174,107 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
     ULONG              status;
     BSTR               fname,iname;
     BSTR               names[10];
-    int                        nrofnames;
+    UINT               nrofnames;
+    DWORD              remoteresult = 0;
+    ITypeInfo          *tinfo;
+    IRpcChannelBuffer *chanbuf;
 
-    hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
+    EnterCriticalSection(&tpinfo->crit);
+
+    hres = _get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname);
     if (hres) {
-       ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
-       return 0;
+        ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
+        ITypeInfo_Release(tinfo);
+        LeaveCriticalSection(&tpinfo->crit);
+        return E_FAIL;
     }
 
-    /*dump_FUNCDESC(fdesc);*/
+    if (!tpinfo->chanbuf)
+    {
+        WARN("Tried to use disconnected proxy\n");
+        ITypeInfo_Release(tinfo);
+        LeaveCriticalSection(&tpinfo->crit);
+        return RPC_E_DISCONNECTED;
+    }
+    chanbuf = tpinfo->chanbuf;
+    IRpcChannelBuffer_AddRef(chanbuf);
+
+    LeaveCriticalSection(&tpinfo->crit);
+
     if (relaydeb) {
-       TRACE_(olerelay)("->");
+       TRACE_(olerelay)("->");
        if (iname)
-           MESSAGE("%s:",debugstr_w(iname));
+           TRACE_(olerelay)("%s:",relaystr(iname));
        if (fname)
-           MESSAGE("%s(%d)",debugstr_w(fname),method);
+           TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
        else
-           MESSAGE("%d",method);
-       MESSAGE("(");
-       if (iname) SysFreeString(iname);
-       if (fname) SysFreeString(fname);
+           TRACE_(olerelay)("%d",method);
+       TRACE_(olerelay)("(");
     }
+
+    if (iname) SysFreeString(iname);
+    if (fname) SysFreeString(fname);
+
+    memset(&buf,0,sizeof(buf));
+
+    /* normal typelib driven serializing */
+
     /* Need them for hack below */
     memset(names,0,sizeof(names));
-    if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
+    if (ITypeInfo_GetNames(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) {
-       xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
-       if (relaydeb) MESSAGE("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
-    } else {
-       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]));
-           }
-           /* 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;
-           }
-           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 serialize param, hres %lx\n",hres);
-               break;
-           }
+    xargs = args;
+    for (i=0;i<fdesc->cParams;i++) {
+       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
+       if (relaydeb) {
+           if (i) TRACE_(olerelay)(",");
+           if (i+1<nrofnames && names[i+1])
+               TRACE_(olerelay)("%s=",relaystr(names[i+1]));
+       }
+       /* No need to marshal other data than FIN and any VT_PTR. */
+       if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags) && (elem->tdesc.vt != VT_PTR)) {
            xargs+=_argsize(elem->tdesc.vt);
+           if (relaydeb) TRACE_(olerelay)("[out]");
+           continue;
        }
+       hres = serialize_param(
+           tinfo,
+           elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags,
+           relaydeb,
+           FALSE,
+           &elem->tdesc,
+           xargs,
+           &buf
+       );
+
+       if (hres) {
+           ERR("Failed to serialize param, hres %lx\n",hres);
+           break;
+       }
+       xargs+=_argsize(elem->tdesc.vt);
     }
-    if (relaydeb) MESSAGE(")");
+    if (relaydeb) TRACE_(olerelay)(")");
+
     memset(&msg,0,sizeof(msg));
     msg.cbBuffer = buf.curoff;
     msg.iMethod  = method;
-    hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
+    hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
     if (hres) {
-       FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
-       return hres;
+       ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
+       goto exit;
     }
     memcpy(msg.Buffer,buf.base,buf.curoff);
-    if (relaydeb) MESSAGE("\n");
-    hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
+    if (relaydeb) TRACE_(olerelay)("\n");
+    hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
     if (hres) {
-       FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres);
-       return hres;
+       ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);
+       goto exit;
     }
-    relaydeb = TRACE_ON(olerelay);
-    if (relaydeb) MESSAGE(" = %08lx (",status);
+
+    if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status);
     if (buf.base)
        buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
     else
@@ -1256,124 +1282,227 @@ xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
     buf.size = msg.cbBuffer;
     memcpy(buf.base,msg.Buffer,buf.size);
     buf.curoff = 0;
-    if (method == 0) {
-       _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
-       if (relaydeb) MESSAGE("[in],%p",*((DWORD**)args[1]));
-    } else {
-       xargs = args;
-       for (i=0;i<fdesc->cParams;i++) {
-           ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
-           BOOL        isdeserialized = FALSE;
-
-           if (relaydeb) {
-               if (i) MESSAGE(",");
-               if (i+1<nrofnames && names[i+1]) MESSAGE("%s=",debugstr_w(names[i+1]));
-           }
-           /* No need to marshal other data than FOUT I think */
-           if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
-               xargs += _argsize(elem->tdesc.vt);
-               if (relaydeb) MESSAGE("[in]");
-               continue;
-           }
-           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;
-           }
+
+    /* generic deserializer using typelib description */
+    xargs = args;
+    status = S_OK;
+    for (i=0;i<fdesc->cParams;i++) {
+       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
+
+       if (relaydeb) {
+           if (i) TRACE_(olerelay)(",");
+           if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
+       }
+       /* No need to marshal other data than FOUT and any VT_PTR */
+       if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) && (elem->tdesc.vt != VT_PTR)) {
            xargs += _argsize(elem->tdesc.vt);
+           if (relaydeb) TRACE_(olerelay)("[in]");
+           continue;
        }
+       hres = deserialize_param(
+           tinfo,
+           elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+           relaydeb,
+           FALSE,
+           &(elem->tdesc),
+           xargs,
+           &buf
+        );
+       if (hres) {
+           ERR("Failed to unmarshall param, hres %lx\n",hres);
+           status = hres;
+           break;
+       }
+       xargs += _argsize(elem->tdesc.vt);
     }
-    if (relaydeb) MESSAGE(")\n\n");
+
+    hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
+    if (hres != S_OK)
+        goto exit;
+    if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult);
+
+    hres = remoteresult;
+
+exit:
     HeapFree(GetProcessHeap(),0,buf.base);
-    return status;
+    IRpcChannelBuffer_Release(chanbuf);
+    ITypeInfo_Release(tinfo);
+    TRACE("-- 0x%08lx\n", hres);
+    return hres;
+}
+
+HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    TMProxyImpl *proxy = (TMProxyImpl *)iface;
+
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+
+    if (proxy->outerunknown)
+        return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
+
+    FIXME("No interface\n");
+    return E_NOINTERFACE;
+}
+
+ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
+{
+    TMProxyImpl *proxy = (TMProxyImpl *)iface;
+
+    TRACE("\n");
+
+    if (proxy->outerunknown)
+        return IUnknown_AddRef(proxy->outerunknown);
+
+    return 2; /* FIXME */
+}
+
+ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
+{
+    TMProxyImpl *proxy = (TMProxyImpl *)iface;
+
+    TRACE("\n");
+
+    if (proxy->outerunknown)
+        return IUnknown_Release(proxy->outerunknown);
+
+    return 1; /* FIXME */
+}
+
+static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr;
+
+    TRACE("(%p)\n", pctinfo);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr = S_OK;
+
+    TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr;
+
+    TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
+                                     cNames, lcid, rgDispId);
+
+    return hr;
+}
+
+static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+                                            WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
+                                            EXCEPINFO * pExcepInfo, UINT * puArgErr)
+{
+    TMProxyImpl *This = (TMProxyImpl *)iface;
+    HRESULT hr;
+
+    TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    if (!This->dispatch)
+    {
+        hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
+                                     (LPVOID *)&This->dispatch);
+    }
+    if (This->dispatch)
+        hr = IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
+                              wFlags, pDispParams, pVarResult, pExcepInfo,
+                              puArgErr);
+
+    return hr;
 }
 
 static HRESULT WINAPI
 PSFacBuf_CreateProxy(
     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
-    IRpcProxyBuffer **ppProxy, LPVOID *ppv
-{
+    IRpcProxyBuffer **ppProxy, LPVOID *ppv)
+{
     HRESULT    hres;
     ITypeInfo  *tinfo;
     int                i, nroffuncs;
-    FUNCDESC   *fdesc;
+    const FUNCDESC *fdesc;
     TMProxyImpl        *proxy;
+    TYPEATTR   *typeattr;
 
     TRACE("(...%s...)\n",debugstr_guid(riid));
     hres = _get_typeinfo_for_iid(riid,&tinfo);
     if (hres) {
-       FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
+       ERR("No typeinfo for %s?\n",debugstr_guid(riid));
        return hres;
     }
     nroffuncs = _nroffuncs(tinfo);
-    proxy = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMProxyImpl));
+    proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
     if (!proxy) return E_OUTOFMEMORY;
-    proxy->asmstubs=HeapAlloc(GetProcessHeap(),0,sizeof(TMAsmProxy)*nroffuncs);
 
     assert(sizeof(TMAsmProxy) == 12);
 
+    proxy->dispatch = NULL;
+    proxy->outerunknown = pUnkOuter;
+    proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+    if (!proxy->asmstubs) {
+        ERR("Could not commit pages for proxy thunks\n");
+        CoTaskMemFree(proxy);
+        return E_OUTOFMEMORY;
+    }
+
+    InitializeCriticalSection(&proxy->crit);
+
     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
     for (i=0;i<nroffuncs;i++) {
-       int             nrofargs;
        TMAsmProxy      *xasm = proxy->asmstubs+i;
 
-       /* nrofargs without This */
        switch (i) {
-       case 0: nrofargs = 2;
+       case 0:
+               proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
                break;
-       case 1: case 2: nrofargs = 0;
+       case 1:
+               proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
+               break;
+       case 2:
+               proxy->lpvtbl[i] = ProxyIUnknown_Release;
                break;
        default: {
                int j;
-               hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
+               /* nrofargs without This */
+               int nrofargs;
+                ITypeInfo *tinfo2;
+               hres = _get_funcdesc(tinfo,i,&tinfo2,&fdesc,NULL,NULL);
+                ITypeInfo_Release(tinfo2);
                if (hres) {
-                   FIXME("GetFuncDesc %lx should not fail here.\n",hres);
+                   ERR("GetFuncDesc %lx should not fail here.\n",hres);
                    return hres;
                }
                /* some args take more than 4 byte on the stack */
@@ -1381,13 +1510,11 @@ PSFacBuf_CreateProxy(
                for (j=0;j<fdesc->cParams;j++)
                    nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
 
+#ifdef __i386__
                if (fdesc->callconv != CC_STDCALL) {
                    ERR("calling convention is not stdcall????\n");
                    return E_FAIL;
                }
-               break;
-           }
-       }
 /* popl %eax   -       return ptr
  * pushl <nr>
  * pushl %eax
@@ -1397,29 +1524,54 @@ PSFacBuf_CreateProxy(
  *
  * arg3 arg2 arg1 <method> <returnptr>
  */
-       xasm->popleax   = 0x58;
-       xasm->pushlval  = 0x6a;
-       xasm->nr        = i;
-       xasm->pushleax  = 0x50;
-       xasm->lcall     = 0xe8; /* relative jump */
-       xasm->xcall     = (DWORD)xCall;
-       xasm->xcall     -= (DWORD)&(xasm->lret);
-       xasm->lret      = 0xc2;
-       xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
-       proxy->lpvtbl[i] = (DWORD)xasm;
+               xasm->popleax   = 0x58;
+               xasm->pushlval  = 0x6a;
+               xasm->nr        = i;
+               xasm->pushleax  = 0x50;
+               xasm->lcall     = 0xe8; /* relative jump */
+               xasm->xcall     = (DWORD)xCall;
+               xasm->xcall     -= (DWORD)&(xasm->lret);
+               xasm->lret      = 0xc2;
+               xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
+               proxy->lpvtbl[i] = xasm;
+               break;
+#else
+                FIXME("not implemented on non i386\n");
+                return E_FAIL;
+#endif
+           }
+       }
     }
+
+    /* if we derive from IDispatch then defer to its proxy for its methods */
+    hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
+    if (hres == S_OK)
+    {
+        if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
+        {
+            proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
+            proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
+            proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
+            proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
+        }
+        ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
+    }
+
     proxy->lpvtbl2     = &tmproxyvtable;
-    proxy->ref         = 2;
+    /* one reference for the proxy */
+    proxy->ref         = 1;
     proxy->tinfo       = tinfo;
     memcpy(&proxy->iid,riid,sizeof(*riid));
+    proxy->chanbuf      = 0;
     *ppv               = (LPVOID)proxy;
     *ppProxy           = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
+    IUnknown_AddRef((IUnknown *)*ppv);
     return S_OK;
 }
 
 typedef struct _TMStubImpl {
-    ICOM_VTABLE(IRpcStubBuffer)        *lpvtbl;
-    DWORD                      ref;
+    const IRpcStubBufferVtbl   *lpvtbl;
+    LONG                       ref;
 
     LPUNKNOWN                  pUnk;
     ITypeInfo                  *tinfo;
@@ -1427,7 +1579,8 @@ typedef struct _TMStubImpl {
 } TMStubImpl;
 
 static HRESULT WINAPI
-TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
+TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
+{
     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
        *ppv = (LPVOID)iface;
        IRpcStubBuffer_AddRef(iface);
@@ -1438,27 +1591,39 @@ TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
 }
 
 static ULONG WINAPI
-TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) {
-    ICOM_THIS(TMStubImpl,iface);
+TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
+    ULONG refCount = InterlockedIncrement(&This->ref);
+        
+    TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
 
-    This->ref++;
-    return This->ref;
+    return refCount;
 }
 
 static ULONG WINAPI
-TMStubImpl_Release(LPRPCSTUBBUFFER iface) {
-    ICOM_THIS(TMStubImpl,iface);
-
-    This->ref--;
-    if (This->ref)
-       return This->ref;
-    HeapFree(GetProcessHeap(),0,This);
-    return 0;
+TMStubImpl_Release(LPRPCSTUBBUFFER iface)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
+    ULONG refCount = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
+
+    if (!refCount)
+    {
+        IRpcStubBuffer_Disconnect(iface);
+        ITypeInfo_Release(This->tinfo);
+        CoTaskMemFree(This);
+    }
+    return refCount;
 }
 
 static HRESULT WINAPI
-TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) {
-    ICOM_THIS(TMStubImpl,iface);
+TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
+
+    TRACE("(%p)->(%p)\n", This, pUnkServer);
 
     IUnknown_AddRef(pUnkServer);
     This->pUnk = pUnkServer;
@@ -1466,53 +1631,65 @@ TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) {
 }
 
 static void WINAPI
-TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) {
-    ICOM_THIS(TMStubImpl,iface);
+TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
 
-    IUnknown_Release(This->pUnk);
-    This->pUnk = NULL;
-    return;
+    TRACE("(%p)->()\n", This);
+
+    if (This->pUnk)
+    {
+        IUnknown_Release(This->pUnk);
+        This->pUnk = NULL;
+    }
 }
 
 static HRESULT WINAPI
 TMStubImpl_Invoke(
-    LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf
-{
+    LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
+{
     int                i;
-    FUNCDESC   *fdesc;
-    ICOM_THIS(TMStubImpl,iface);
+    const FUNCDESC *fdesc;
+    TMStubImpl *This = (TMStubImpl *)iface;
     HRESULT    hres;
     DWORD      *args, res, *xargs, nrofargs;
     marshal_state      buf;
-    int                nrofnames;
+    UINT       nrofnames;
     BSTR       names[10];
+    BSTR       iname = NULL;
+    ITypeInfo  *tinfo;
 
     memset(&buf,0,sizeof(buf));
     buf.size   = xmsg->cbBuffer;
-    buf.base   = xmsg->Buffer;
+    buf.base   = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
+    memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
     buf.curoff = 0;
-    buf.iid    = IID_IUnknown;
 
     TRACE("...\n");
-    if (xmsg->iMethod == 0) { /* QI */
-       IID             xiid;
-       /* in: IID, out: <iface> */
-
-       xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
-       buf.curoff = 0;
-       hres = _marshal_interface(&buf,&xiid,This->pUnk);
-       xmsg->Buffer    = buf.base; /* Might have been reallocated */
-       xmsg->cbBuffer  = buf.size;
-       return hres;
+
+    if (xmsg->iMethod < 3) {
+        ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
+        return E_UNEXPECTED;
     }
-    hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
+
+    hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL);
     if (hres) {
-       FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
+       ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
        return hres;
     }
+
+    if (iname && !lstrcmpW(iname, IDispatchW))
+    {
+        ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
+        ITypeInfo_Release(tinfo);
+        return E_UNEXPECTED;
+    }
+
+    if (iname) SysFreeString (iname);
+
     /* Need them for hack below */
     memset(names,0,sizeof(names));
-    ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
+    ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
     if (nrofnames > sizeof(names)/sizeof(names[0])) {
        ERR("Need more names!\n");
     }
@@ -1528,133 +1705,84 @@ TMStubImpl_Invoke(
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
        ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
-       BOOL            isdeserialized = 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);
-
-           /* 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
-           );
+       hres = deserialize_param(
+          tinfo,
+          elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags,
+          FALSE,
+          TRUE,
+          &(elem->tdesc),
+          xargs,
+          &buf
+       );
        xargs += _argsize(elem->tdesc.vt);
        if (hres) {
-           FIXME("Failed to deserialize param %s, hres %lx\n",debugstr_w(names[i+1]),hres);
+           ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
            break;
        }
     }
-    hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
-    if (hres) {
-       ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
-       return hres;
-    }
+
+    args[0] = (DWORD)This->pUnk;
     res = _invoke(
-           (*((FARPROC**)args[0]))[fdesc->oVft/4],
-           fdesc->callconv,
-           (xargs-args),
-           args
+       (*((FARPROC**)args[0]))[fdesc->oVft/4],
+       fdesc->callconv,
+       (xargs-args),
+       args
     );
-    IUnknown_Release((LPUNKNOWN)args[0]);
     buf.curoff = 0;
+
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
        ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
-       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
-           );
+       hres = serialize_param(
+          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);
+           ERR("Failed to stuballoc param, hres %lx\n",hres);
            break;
        }
     }
-    /* might need to use IRpcChannelBuffer_GetBuffer ? */
+
+    hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
+    if (hres != S_OK)
+       return hres;
+
+    ITypeInfo_Release(tinfo);
+    HeapFree(GetProcessHeap(), 0, args);
+
     xmsg->cbBuffer     = buf.curoff;
-    xmsg->Buffer       = buf.base;
-    HeapFree(GetProcessHeap(),0,args);
-    return res;
+    if (rpcchanbuf)
+    {
+        hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
+        if (hres != S_OK)
+            ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08lx\n", hres);
+    }
+    else
+    {
+        /* FIXME: remove this case when we start sending an IRpcChannelBuffer
+         * object with builtin OLE */
+        RPC_STATUS status = I_RpcGetBuffer((RPC_MESSAGE *)xmsg);
+        if (status != RPC_S_OK)
+        {
+            ERR("I_RpcGetBuffer failed with error %ld\n", status);
+            hres = E_FAIL;
+        }
+    }
+
+    if (hres == S_OK)
+        memcpy(xmsg->Buffer, buf.base, buf.curoff);
+
+    HeapFree(GetProcessHeap(), 0, buf.base);
+
+    TRACE("returning\n");
+    return hres;
 }
 
 static LPRPCSTUBBUFFER WINAPI
@@ -1665,8 +1793,9 @@ TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
 
 static ULONG WINAPI
 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
-    ICOM_THIS(TMStubImpl,iface);
+    TMStubImpl *This = (TMStubImpl *)iface;
 
+    FIXME("()\n");
     return This->ref; /*FIXME? */
 }
 
@@ -1680,8 +1809,7 @@ TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
     return;
 }
 
-ICOM_VTABLE(IRpcStubBuffer) tmstubvtbl = {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+static const IRpcStubBufferVtbl tmstubvtbl = {
     TMStubImpl_QueryInterface,
     TMStubImpl_AddRef,
     TMStubImpl_Release,
@@ -1706,10 +1834,10 @@ PSFacBuf_CreateStub(
     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
     hres = _get_typeinfo_for_iid(riid,&tinfo);
     if (hres) {
-       FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
+       ERR("No typeinfo for %s?\n",debugstr_guid(riid));
        return hres;
     }
-    stub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMStubImpl));
+    stub = CoTaskMemAlloc(sizeof(TMStubImpl));
     if (!stub)
        return E_OUTOFMEMORY;
     stub->lpvtbl       = &tmstubvtbl;
@@ -1718,13 +1846,13 @@ PSFacBuf_CreateStub(
     memcpy(&(stub->iid),riid,sizeof(*riid));
     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
     *ppStub            = (LPRPCSTUBBUFFER)stub;
+    TRACE("IRpcStubBuffer: %p\n", stub);
     if (hres)
-       FIXME("Connect to pUnkServer failed?\n");
+       ERR("Connect to pUnkServer failed?\n");
     return hres;
 }
 
-static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
-    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+static const IPSFactoryBufferVtbl psfacbufvtbl = {
     PSFacBuf_QueryInterface,
     PSFacBuf_AddRef,
     PSFacBuf_Release,
@@ -1733,13 +1861,12 @@ static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
 };
 
 /* This is the whole PSFactoryBuffer object, just the vtableptr */
-static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
+static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
 
 /***********************************************************************
- *           DllGetClassObject [OLE32.63]
+ *           TMARSHAL_DllGetClassObject
  */
-HRESULT WINAPI
-TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
+HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
 {
     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
        *ppv = &lppsfac;