Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / oleaut32 / tmarshal.c
index 9159122..50a9135 100644 (file)
-/*\r
- *     TYPELIB Marshaler\r
- *\r
- *     Copyright 2002,2005     Marcus Meissner\r
- *\r
- * The olerelay debug channel allows you to see calls marshalled by\r
- * the typelib marshaller. It is not a generic COM relaying system.\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-#include "config.h"\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <ctype.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "winerror.h"\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winnls.h"\r
-#include "winreg.h"\r
-#include "winuser.h"\r
-\r
-#include "ole2.h"\r
-#include "typelib.h"\r
-#include "wine/debug.h"\r
-\r
-static const WCHAR riidW[5] = {'r','i','i','d',0};\r
-static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};\r
-static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};\r
-static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};\r
-static const WCHAR GetIDsOfNamesW[] = { 'G','e','t','I','D','s','O','f','N','a','m','e','s',0};\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-WINE_DECLARE_DEBUG_CHANNEL(olerelay);\r
-\r
-#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))\r
-\r
-typedef struct _marshal_state {\r
-    LPBYTE     base;\r
-    int                size;\r
-    int                curoff;\r
-\r
-    BOOL       thisisiid;\r
-    IID                iid;    /* HACK: for VT_VOID */\r
-} marshal_state;\r
-\r
-/* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */\r
-static char *relaystr(WCHAR *in) {\r
-    char *tmp = (char *)debugstr_w(in);\r
-    tmp += 2;\r
-    tmp[strlen(tmp)-1] = '\0';\r
-    return tmp;\r
-}\r
-\r
-static HRESULT\r
-xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {\r
-    while (buf->size - buf->curoff < size) {\r
-       if (buf->base) {\r
-           buf->size += 100;\r
-           buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);\r
-           if (!buf->base)\r
-               return E_OUTOFMEMORY;\r
-       } else {\r
-           buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);\r
-           buf->size = 32;\r
-           if (!buf->base)\r
-               return E_OUTOFMEMORY;\r
-       }\r
-    }\r
-    memcpy(buf->base+buf->curoff,stuff,size);\r
-    buf->curoff += size;\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {\r
-    if (buf->size < buf->curoff+size) return E_FAIL;\r
-    memcpy(stuff,buf->base+buf->curoff,size);\r
-    buf->curoff += size;\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-xbuf_skip(marshal_state *buf, DWORD size) {\r
-    if (buf->size < buf->curoff+size) return E_FAIL;\r
-    buf->curoff += size;\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-_unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {\r
-    IStream            *pStm;\r
-    ULARGE_INTEGER     newpos;\r
-    LARGE_INTEGER      seekto;\r
-    ULONG              res;\r
-    HRESULT            hres;\r
-    DWORD              xsize;\r
-\r
-    TRACE("...%s...\n",debugstr_guid(riid));\r
-    \r
-    *pUnk = NULL;\r
-    hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));\r
-    if (hres) {\r
-        ERR("xbuf_get failed\n");\r
-        return hres;\r
-    }\r
-    \r
-    if (xsize == 0) return S_OK;\r
-    \r
-    hres = CreateStreamOnHGlobal(0,TRUE,&pStm);\r
-    if (hres) {\r
-       ERR("Stream create failed %lx\n",hres);\r
-       return hres;\r
-    }\r
-    \r
-    hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);\r
-    if (hres) {\r
-        ERR("stream write %lx\n",hres);\r
-        return hres;\r
-    }\r
-    \r
-    memset(&seekto,0,sizeof(seekto));\r
-    hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);\r
-    if (hres) {\r
-        ERR("Failed Seek %lx\n",hres);\r
-        return hres;\r
-    }\r
-    \r
-    hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);\r
-    if (hres) {\r
-       ERR("Unmarshalling interface %s failed with %lx\n",debugstr_guid(riid),hres);\r
-       return hres;\r
-    }\r
-    \r
-    IStream_Release(pStm);\r
-    return xbuf_skip(buf,xsize);\r
-}\r
-\r
-static HRESULT\r
-_marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {\r
-    LPUNKNOWN          newiface = NULL;\r
-    LPBYTE             tempbuf = NULL;\r
-    IStream            *pStm = NULL;\r
-    STATSTG            ststg;\r
-    ULARGE_INTEGER     newpos;\r
-    LARGE_INTEGER      seekto;\r
-    ULONG              res;\r
-    DWORD              xsize;\r
-    HRESULT            hres;\r
-\r
-    if (!pUnk) {\r
-       /* this is valid, if for instance we serialize\r
-        * a VT_DISPATCH with NULL ptr which apparently\r
-        * can happen. S_OK to make sure we continue\r
-        * serializing.\r
-        */\r
-        ERR("pUnk is NULL?\n");\r
-        xsize = 0;\r
-        return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));\r
-    }\r
-\r
-    hres = E_FAIL;\r
-\r
-    TRACE("...%s...\n",debugstr_guid(riid));\r
-    hres = IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);\r
-    if (hres) {\r
-       WARN("%p does not support iface %s\n",pUnk,debugstr_guid(riid));\r
-       goto fail;\r
-    }\r
-    \r
-    hres = CreateStreamOnHGlobal(0,TRUE,&pStm);\r
-    if (hres) {\r
-       ERR("Stream create failed %lx\n",hres);\r
-       goto fail;\r
-    }\r
-    \r
-    hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);\r
-    if (hres) {\r
-       ERR("Marshalling interface %s failed with %lx\n", debugstr_guid(riid), hres);\r
-       goto fail;\r
-    }\r
-    \r
-    hres = IStream_Stat(pStm,&ststg,0);\r
-    if (hres) {\r
-        ERR("Stream stat failed\n");\r
-        goto fail;\r
-    }\r
-    \r
-    tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);\r
-    memset(&seekto,0,sizeof(seekto));\r
-    hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);\r
-    if (hres) {\r
-        ERR("Failed Seek %lx\n",hres);\r
-        goto fail;\r
-    }\r
-    \r
-    hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);\r
-    if (hres) {\r
-        ERR("Failed Read %lx\n",hres);\r
-        goto fail;\r
-    }\r
-    \r
-    xsize = ststg.cbSize.u.LowPart;\r
-    xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));\r
-    hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);\r
-    \r
-    HeapFree(GetProcessHeap(),0,tempbuf);\r
-    IUnknown_Release(newiface);\r
-    IStream_Release(pStm);\r
-    \r
-    return hres;\r
-    \r
-fail:\r
-    xsize = 0;\r
-    xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));\r
-    if (pStm) IUnknown_Release(pStm);\r
-    if (newiface) IUnknown_Release(newiface);\r
-    HeapFree(GetProcessHeap(), 0, tempbuf);\r
-    return hres;\r
-}\r
-\r
-/********************* OLE Proxy/Stub Factory ********************************/\r
-static HRESULT WINAPI\r
-PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {\r
-    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {\r
-       *ppv = (LPVOID)iface;\r
-       /* No ref counting, static class */\r
-       return S_OK;\r
-    }\r
-    FIXME("(%s) unknown IID?\n",debugstr_guid(iid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }\r
-static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }\r
-\r
-static HRESULT\r
-_get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {\r
-    HRESULT    hres;\r
-    HKEY       ikey;\r
-    char       tlguid[200],typelibkey[300],interfacekey[300],ver[100];\r
-    char       tlfn[260];\r
-    OLECHAR    tlfnW[260];\r
-    DWORD      tlguidlen, verlen, type, tlfnlen;\r
-    ITypeLib   *tl;\r
-\r
-    sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",\r
-       riid->Data1, riid->Data2, riid->Data3,\r
-       riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],\r
-       riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]\r
-    );\r
-\r
-    if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {\r
-       ERR("No %s key found.\n",interfacekey);\r
-               return E_FAIL;\r
-    }\r
-    type = (1<<REG_SZ);\r
-    tlguidlen = sizeof(tlguid);\r
-    if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {\r
-       ERR("Getting typelib guid failed.\n");\r
-       RegCloseKey(ikey);\r
-       return E_FAIL;\r
-    }\r
-    type = (1<<REG_SZ);\r
-    verlen = sizeof(ver);\r
-    if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {\r
-       ERR("Could not get version value?\n");\r
-       RegCloseKey(ikey);\r
-       return E_FAIL;\r
-    }\r
-    RegCloseKey(ikey);\r
-    sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);\r
-    tlfnlen = sizeof(tlfn);\r
-    if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {\r
-       ERR("Could not get typelib fn?\n");\r
-       return E_FAIL;\r
-    }\r
-    MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);\r
-    hres = LoadTypeLib(tlfnW,&tl);\r
-    if (hres) {\r
-       ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));\r
-       return hres;\r
-    }\r
-    hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);\r
-    if (hres) {\r
-       ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));\r
-       ITypeLib_Release(tl);\r
-       return hres;\r
-    }\r
-    /* FIXME: do this?  ITypeLib_Release(tl); */\r
-    return hres;\r
-}\r
-\r
-/* Determine nr of functions. Since we use the toplevel interface and all\r
- * inherited ones have lower numbers, we are ok to not to descent into\r
- * the inheritance tree I think.\r
- */\r
-static int _nroffuncs(ITypeInfo *tinfo) {\r
-    int        n, max = 0;\r
-    FUNCDESC   *fdesc;\r
-    HRESULT    hres;\r
-\r
-    n=0;\r
-    while (1) {\r
-       hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);\r
-       if (hres)\r
-           return max+1;\r
-       if (fdesc->oVft/4 > max)\r
-           max = fdesc->oVft/4;\r
-       n++;\r
-    }\r
-    /*NOTREACHED*/\r
-}\r
-\r
-#ifdef __i386__\r
-\r
-#include "pshpack1.h"\r
-\r
-typedef struct _TMAsmProxy {\r
-    BYTE       popleax;\r
-    BYTE       pushlval;\r
-    BYTE       nr;\r
-    BYTE       pushleax;\r
-    BYTE       lcall;\r
-    DWORD      xcall;\r
-    BYTE       lret;\r
-    WORD       bytestopop;\r
-} TMAsmProxy;\r
-\r
-#include "poppack.h"\r
-\r
-#else /* __i386__ */\r
-# error You need to implement stubless proxies for your architecture\r
-#endif\r
-\r
-typedef struct _TMProxyImpl {\r
-    LPVOID                             *lpvtbl;\r
-    IRpcProxyBufferVtbl        *lpvtbl2;\r
-    ULONG                              ref;\r
-\r
-    TMAsmProxy                         *asmstubs;\r
-    ITypeInfo*                         tinfo;\r
-    IRpcChannelBuffer*                 chanbuf;\r
-    IID                                        iid;\r
-    CRITICAL_SECTION   crit;\r
-    IUnknown                           *outerunknown;\r
-} TMProxyImpl;\r
-\r
-static HRESULT WINAPI\r
-TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)\r
-{\r
-    TRACE("()\n");\r
-    if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {\r
-        *ppv = (LPVOID)iface;\r
-        IRpcProxyBuffer_AddRef(iface);\r
-        return S_OK;\r
-    }\r
-    FIXME("no interface for %s\n",debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI\r
-TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)\r
-{\r
-    ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);\r
-    ULONG refCount = InterlockedIncrement(&This->ref);\r
-\r
-    TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);\r
-\r
-    return refCount;\r
-}\r
-\r
-static ULONG WINAPI\r
-TMProxyImpl_Release(LPRPCPROXYBUFFER iface)\r
-{\r
-    ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);\r
-    ULONG refCount = InterlockedDecrement(&This->ref);\r
-\r
-    TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1);\r
-\r
-    if (!refCount)\r
-    {\r
-        DeleteCriticalSection(&This->crit);\r
-        if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);\r
-        VirtualFree(This->asmstubs, 0, MEM_RELEASE);\r
-        CoTaskMemFree(This);\r
-    }\r
-    return refCount;\r
-}\r
-\r
-static HRESULT WINAPI\r
-TMProxyImpl_Connect(\r
-    LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)\r
-{\r
-    ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);\r
-\r
-    TRACE("(%p)\n", pRpcChannelBuffer);\r
-\r
-    EnterCriticalSection(&This->crit);\r
-\r
-    IRpcChannelBuffer_AddRef(pRpcChannelBuffer);\r
-    This->chanbuf = pRpcChannelBuffer;\r
-\r
-    LeaveCriticalSection(&This->crit);\r
-\r
-    return S_OK;\r
-}\r
-\r
-static void WINAPI\r
-TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)\r
-{\r
-    ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);\r
-\r
-    TRACE("()\n");\r
-\r
-    EnterCriticalSection(&This->crit);\r
-\r
-    IRpcChannelBuffer_Release(This->chanbuf);\r
-    This->chanbuf = NULL;\r
-\r
-    LeaveCriticalSection(&This->crit);\r
-}\r
-\r
-\r
-static IRpcProxyBufferVtbl tmproxyvtable = {\r
-    TMProxyImpl_QueryInterface,\r
-    TMProxyImpl_AddRef,\r
-    TMProxyImpl_Release,\r
-    TMProxyImpl_Connect,\r
-    TMProxyImpl_Disconnect\r
-};\r
-\r
-/* how much space do we use on stack in DWORD steps. */\r
-int\r
-_argsize(DWORD vt) {\r
-    switch (vt) {\r
-    case VT_DATE:\r
-       return sizeof(DATE)/sizeof(DWORD);\r
-    case VT_VARIANT:\r
-       return (sizeof(VARIANT)+3)/sizeof(DWORD);\r
-    default:\r
-       return 1;\r
-    }\r
-}\r
-\r
-static int\r
-_xsize(TYPEDESC *td) {\r
-    switch (td->vt) {\r
-    case VT_DATE:\r
-       return sizeof(DATE);\r
-    case VT_VARIANT:\r
-       return sizeof(VARIANT)+3;\r
-    case VT_CARRAY: {\r
-       int i, arrsize = 1;\r
-       ARRAYDESC *adesc = td->u.lpadesc;\r
-\r
-       for (i=0;i<adesc->cDims;i++)\r
-           arrsize *= adesc->rgbounds[i].cElements;\r
-       return arrsize*_xsize(&adesc->tdescElem);\r
-    }\r
-    case VT_UI2:\r
-    case VT_I2:\r
-       return 2;\r
-    case VT_UI1:\r
-    case VT_I1:\r
-       return 1;\r
-    default:\r
-       return 4;\r
-    }\r
-}\r
-\r
-static HRESULT\r
-serialize_param(\r
-    ITypeInfo          *tinfo,\r
-    BOOL               writeit,\r
-    BOOL               debugout,\r
-    BOOL               dealloc,\r
-    TYPEDESC           *tdesc,\r
-    DWORD              *arg,\r
-    marshal_state      *buf)\r
-{\r
-    HRESULT hres = S_OK;\r
-\r
-    TRACE("(tdesc.vt %d)\n",tdesc->vt);\r
-\r
-    switch (tdesc->vt) {\r
-    case VT_EMPTY: /* nothing. empty variant for instance */\r
-       return S_OK;\r
-    case VT_BOOL:\r
-    case VT_ERROR:\r
-    case VT_UINT:\r
-    case VT_I4:\r
-    case VT_R4:\r
-    case VT_UI4:\r
-       hres = S_OK;\r
-       if (debugout) TRACE_(olerelay)("%lx",*arg);\r
-       if (writeit)\r
-           hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));\r
-       return hres;\r
-    case VT_I2:\r
-    case VT_UI2:\r
-       hres = S_OK;\r
-       if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff);\r
-       if (writeit)\r
-           hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));\r
-       return hres;\r
-    case VT_I1:\r
-    case VT_UI1:\r
-       hres = S_OK;\r
-       if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff);\r
-       if (writeit)\r
-           hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));\r
-       return hres;\r
-    case VT_I4|VT_BYREF:\r
-       hres = S_OK;\r
-       if (debugout) TRACE_(olerelay)("&0x%lx",*arg);\r
-       if (writeit)\r
-           hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD));\r
-       /* do not dealloc at this time */\r
-       return hres;\r
-    case VT_VARIANT: {\r
-       TYPEDESC        tdesc2;\r
-       VARIANT         *vt = (VARIANT*)arg;\r
-       DWORD           vttype = V_VT(vt);\r
-\r
-       if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);\r
-       tdesc2.vt = vttype;\r
-       if (writeit) {\r
-           hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));\r
-           if (hres) return hres;\r
-       }\r
-       /* need to recurse since we need to free the stuff */\r
-       hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);\r
-       if (debugout) TRACE_(olerelay)(")");\r
-       return hres;\r
-    }\r
-    case VT_BSTR|VT_BYREF: {\r
-       if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : "<bstr NULL>");\r
-        if (writeit) {\r
-            /* ptr to ptr to magic widestring, basically */\r
-            BSTR *bstr = (BSTR *) *arg;\r
-            if (!*bstr) {\r
-                /* -1 means "null string" which is equivalent to empty string */\r
-                DWORD fakelen = -1;     \r
-                xbuf_add(buf, (LPBYTE)&fakelen,4);\r
-            } else {\r
-                /* BSTRs store the length behind the first character */\r
-                DWORD *len = ((DWORD *)(*bstr))-1;\r
-                hres = xbuf_add(buf, (LPBYTE) len, *len + 4);\r
-                if (hres) return hres;\r
-            }\r
-        }\r
-\r
-        if (dealloc && arg) {\r
-            BSTR *str = *((BSTR **)arg);\r
-            SysFreeString(*str);\r
-        }\r
-        return S_OK;\r
-    }\r
-    \r
-    case VT_BSTR: {\r
-       if (debugout) {\r
-           if (*arg)\r
-                   TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));\r
-           else\r
-                   TRACE_(olerelay)("<bstr NULL>");\r
-       }\r
-       if (writeit) {\r
-           if (!*arg) {\r
-               DWORD fakelen = -1;\r
-               hres = xbuf_add(buf,(LPBYTE)&fakelen,4);\r
-               if (hres)\r
-                   return hres;\r
-           } else {\r
-               DWORD *bstr = ((DWORD*)(*arg))-1;\r
-\r
-               hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);\r
-               if (hres)\r
-                   return hres;\r
-           }\r
-       }\r
-\r
-       if (dealloc && arg)\r
-           SysFreeString((BSTR)*arg);\r
-       return S_OK;\r
-    }\r
-    case VT_PTR: {\r
-       DWORD cookie;\r
-\r
-       if (debugout) TRACE_(olerelay)("*");\r
-       /* Write always, so the other side knows when it gets a NULL pointer.\r
-        */\r
-       cookie = *arg ? 0x42424242 : 0;\r
-       hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));\r
-       if (hres)\r
-           return hres;\r
-       if (!*arg) {\r
-           if (debugout) TRACE_(olerelay)("NULL");\r
-           return S_OK;\r
-       }\r
-       hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);\r
-       if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);\r
-       return hres;\r
-    }\r
-    case VT_UNKNOWN:\r
-       if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg);\r
-       if (writeit)\r
-           hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);\r
-       return hres;\r
-    case VT_DISPATCH:\r
-       if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg);\r
-       if (writeit)\r
-           hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);\r
-       return hres;\r
-    case VT_VOID:\r
-       if (debugout) TRACE_(olerelay)("<void>");\r
-       return S_OK;\r
-    case VT_USERDEFINED: {\r
-       ITypeInfo       *tinfo2;\r
-       TYPEATTR        *tattr;\r
-\r
-       hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);\r
-       if (hres) {\r
-           ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);\r
-           return hres;\r
-       }\r
-       ITypeInfo_GetTypeAttr(tinfo2,&tattr);\r
-       switch (tattr->typekind) {\r
-       case TKIND_DISPATCH:\r
-       case TKIND_INTERFACE:\r
-           if (writeit)\r
-              hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);\r
-           break;\r
-       case TKIND_RECORD: {\r
-           int i;\r
-           if (debugout) TRACE_(olerelay)("{");\r
-           for (i=0;i<tattr->cVars;i++) {\r
-               VARDESC *vdesc;\r
-               ELEMDESC *elem2;\r
-               TYPEDESC *tdesc2;\r
-\r
-               hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);\r
-               if (hres) {\r
-                   ERR("Could not get vardesc of %d\n",i);\r
-                   return hres;\r
-               }\r
-               /* Need them for hack below */\r
-               /*\r
-               memset(names,0,sizeof(names));\r
-               hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);\r
-               if (nrofnames > sizeof(names)/sizeof(names[0])) {\r
-                   ERR("Need more names!\n");\r
-               }\r
-               if (!hres && debugout)\r
-                   TRACE_(olerelay)("%s=",relaystr(names[0]));\r
-               */\r
-               elem2 = &vdesc->elemdescVar;\r
-               tdesc2 = &elem2->tdesc;\r
-               hres = serialize_param(\r
-                   tinfo2,\r
-                   writeit,\r
-                   debugout,\r
-                   dealloc,\r
-                   tdesc2,\r
-                   (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),\r
-                   buf\r
-               );\r
-               if (hres!=S_OK)\r
-                   return hres;\r
-               if (debugout && (i<(tattr->cVars-1)))\r
-                   TRACE_(olerelay)(",");\r
-           }\r
-           if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))\r
-               memcpy(&(buf->iid),arg,sizeof(buf->iid));\r
-           if (debugout) TRACE_(olerelay)("}");\r
-           break;\r
-       }\r
-       default:\r
-           FIXME("Unhandled typekind %d\n",tattr->typekind);\r
-           hres = E_FAIL;\r
-           break;\r
-       }\r
-       ITypeInfo_Release(tinfo2);\r
-       return hres;\r
-    }\r
-    case VT_CARRAY: {\r
-       ARRAYDESC *adesc = tdesc->u.lpadesc;\r
-       int i, arrsize = 1;\r
-\r
-       if (debugout) TRACE_(olerelay)("carr");\r
-       for (i=0;i<adesc->cDims;i++) {\r
-           if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);\r
-           arrsize *= adesc->rgbounds[i].cElements;\r
-       }\r
-       if (debugout) TRACE_(olerelay)("(vt %d)",adesc->tdescElem.vt);\r
-       if (debugout) TRACE_(olerelay)("[");\r
-       for (i=0;i<arrsize;i++) {\r
-           hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);\r
-           if (hres)\r
-               return hres;\r
-           if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");\r
-       }\r
-       if (debugout) TRACE_(olerelay)("]");\r
-       return S_OK;\r
-    }\r
-    default:\r
-       ERR("Unhandled marshal type %d.\n",tdesc->vt);\r
-       return S_OK;\r
-    }\r
-}\r
-\r
-/* IDL desc:\r
- * HRESULT GetIDsOfNames(\r
- *   [in] REFIID riid,                                 args[1]\r
- *   [in, size_is(cNames)] LPOLESTR *rgszNames,                args[2]\r
- *   [in] UINT cNames,                                 args[3]\r
- *   [in] LCID lcid,                                   args[4]\r
- *   [out, size_is(cNames)] DISPID *rgDispId);         args[5]\r
- *\r
- * line format:\r
- *     IID     iid;\r
- *     DWORD   cNames;\r
- *     LPOLESTR rgszNames[cNames];\r
- *             DWORD bytestrlen        (incl 0)\r
- *             BYTE data[bytestrlen]   (incl 0)\r
- *     LCID\r
- */\r
-static HRESULT\r
-serialize_IDispatch_GetIDsOfNames(\r
-    BOOL               inputparams,\r
-    BOOL               debugout,\r
-    DWORD              *args,\r
-    marshal_state      *buf)\r
-{\r
-    HRESULT    hres;\r
-    DWORD      cNames = args[2];\r
-    LPOLESTR    *rgszNames = (LPOLESTR*)args[1];\r
-    int                i;\r
-\r
-    if (inputparams) {\r
-       if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0]));\r
-       hres = xbuf_add(buf, (LPBYTE)args[0], sizeof(IID));\r
-       if (hres) {\r
-           FIXME("serialize of IID failed.\n");\r
-           return hres;\r
-       }\r
-       if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames);\r
-       hres = xbuf_add(buf, (LPBYTE)&cNames, sizeof(DWORD));\r
-       if (hres) {\r
-           FIXME("serialize of cNames failed.\n");\r
-           return hres;\r
-       }\r
-       if (debugout) TRACE_(olerelay)("rgszNames=[");\r
-        for (i=0;i<cNames;i++) {\r
-           DWORD len = 2*(lstrlenW(rgszNames[i])+1);\r
-\r
-           if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i]));\r
-           hres = xbuf_add(buf, (LPBYTE)&len, sizeof(DWORD));\r
-           if (hres) {\r
-               FIXME("serialize of len failed.\n");\r
-               return hres;\r
-           }\r
-           hres = xbuf_add(buf, (LPBYTE)rgszNames[i], len);\r
-           if (hres) {\r
-               FIXME("serialize of rgszNames[i] failed.\n");\r
-               return hres;\r
-           }\r
-        }\r
-       if (debugout) TRACE_(olerelay)("],lcid=%04lx)",args[3]);\r
-       hres = xbuf_add(buf, (LPBYTE)&args[3], sizeof(DWORD));\r
-       if (hres) {\r
-           FIXME("serialize of lcid failed.\n");\r
-           return hres;\r
-       }\r
-    } else {\r
-       DISPID *rgDispId = (DISPID*)args[4];\r
-\r
-       hres = xbuf_add(buf, (LPBYTE)rgDispId, sizeof(DISPID) * cNames);\r
-       if (hres) {\r
-           FIXME("serialize of rgDispId failed.\n");\r
-           return hres;\r
-       }\r
-       if (debugout) {\r
-           TRACE_(olerelay)("riid=[in],rgszNames=[in],cNames=[in],rgDispId=[");\r
-           for (i=0;i<cNames;i++)\r
-               TRACE_(olerelay)("%08lx,",rgDispId[i]);\r
-           TRACE_(olerelay)("])");\r
-       }\r
-       HeapFree(GetProcessHeap(),0,(IID*)args[0]);\r
-       rgszNames = (LPOLESTR*)args[1];\r
-       for (i=0;i<cNames;i++) HeapFree(GetProcessHeap(),0,rgszNames[i]);\r
-       HeapFree(GetProcessHeap(),0,rgszNames);\r
-       HeapFree(GetProcessHeap(),0,rgDispId);\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-deserialize_IDispatch_GetIDsOfNames(\r
-    BOOL               inputparams,\r
-    BOOL               debugout,\r
-    DWORD              *args,\r
-    marshal_state      *buf)\r
-{\r
-    HRESULT    hres;\r
-    DWORD      cNames;\r
-    LPOLESTR    *rgszNames;\r
-    int                i;\r
-\r
-    if (inputparams) {\r
-       args[0] = (DWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IID));\r
-       if (!args[0]) return E_FAIL;\r
-       hres = xbuf_get(buf, (LPBYTE)args[0], sizeof(IID));\r
-       if (hres) {\r
-           FIXME("deserialize of IID failed.\n");\r
-           return hres;\r
-       }\r
-       if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0]));\r
-\r
-       hres = xbuf_get(buf, (LPBYTE)&cNames, sizeof(DWORD));\r
-       if (hres) {\r
-           FIXME("deserialize of cNames failed.\n");\r
-           return hres;\r
-       }\r
-        args[2] = cNames;\r
-       if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames);\r
-       if (debugout) TRACE_(olerelay)("rgszNames=[");\r
-        rgszNames = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPOLESTR) * cNames);\r
-       if (!rgszNames) return E_FAIL;\r
-       args[1] = (DWORD)rgszNames;\r
-        for (i=0;i<cNames;i++) {\r
-           DWORD len;\r
-\r
-           hres = xbuf_get(buf, (LPBYTE)&len, sizeof(DWORD));\r
-           if (hres) {\r
-               FIXME("serialize of len failed.\n");\r
-               return hres;\r
-           }\r
-           rgszNames[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);\r
-           if (!rgszNames[i]) {\r
-               FIXME("heapalloc of %ld bytes failed\n", len);\r
-               return E_FAIL;\r
-           }\r
-           hres = xbuf_get(buf, (LPBYTE)rgszNames[i], len);\r
-           if (hres) {\r
-               FIXME("serialize of rgszNames[i] failed.\n");\r
-               return hres;\r
-           }\r
-           if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i]));\r
-        }\r
-       hres = xbuf_get(buf, (LPBYTE)&args[3], sizeof(DWORD));\r
-       if (hres) {\r
-           FIXME("deserialize of lcid failed.\n");\r
-           return hres;\r
-       }\r
-       if (debugout) TRACE_(olerelay)("],lcid=%04lx,rgDispId=[out])",args[3]);\r
-        args[4] = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID) * cNames);\r
-    } else {\r
-       hres = xbuf_get(buf, (LPBYTE)args[4], sizeof(DISPID) * args[2]);\r
-       if (hres) {\r
-           FIXME("serialize of rgDispId failed.\n");\r
-           return hres;\r
-       }\r
-       if (debugout) {\r
-           TRACE_(olerelay)("dispid=[");\r
-           for (i=0;i<args[2];i++)\r
-               TRACE_(olerelay)("%08lx,",((DISPID*)args[4])[i]);\r
-           TRACE_(olerelay)("])");\r
-       }\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-serialize_LPVOID_ptr(\r
-    ITypeInfo          *tinfo,\r
-    BOOL               writeit,\r
-    BOOL               debugout,\r
-    BOOL               dealloc,\r
-    TYPEDESC           *tdesc,\r
-    DWORD              *arg,\r
-    marshal_state      *buf)\r
-{\r
-    HRESULT    hres;\r
-    DWORD      cookie;\r
-\r
-    if ((tdesc->vt != VT_PTR)                  ||\r
-       (tdesc->u.lptdesc->vt != VT_PTR)        ||\r
-       (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)\r
-    ) {\r
-       FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");\r
-       return E_FAIL;\r
-    }\r
-    cookie = (*(DWORD*)*arg) ? 0x42424242: 0x0;\r
-    if (writeit) {\r
-       hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));\r
-       if (hres)\r
-           return hres;\r
-    }\r
-    if (!*(DWORD*)*arg) {\r
-       if (debugout) TRACE_(olerelay)("<lpvoid NULL>");\r
-       return S_OK;\r
-    }\r
-    if (debugout)\r
-       TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg);\r
-    if (writeit) {\r
-       hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);\r
-       if (hres)\r
-           return hres;\r
-    }\r
-    if (dealloc)\r
-       HeapFree(GetProcessHeap(),0,(LPVOID)*arg);\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-serialize_DISPPARAM_ptr(\r
-    ITypeInfo          *tinfo,\r
-    BOOL               writeit,\r
-    BOOL               debugout,\r
-    BOOL               dealloc,\r
-    TYPEDESC           *tdesc,\r
-    DWORD              *arg,\r
-    marshal_state      *buf)\r
-{\r
-    DWORD      cookie;\r
-    HRESULT    hres;\r
-    DISPPARAMS *disp;\r
-    int                i;\r
-\r
-    if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {\r
-       FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");\r
-       return E_FAIL;\r
-    }\r
-\r
-    cookie = *arg ? 0x42424242 : 0x0;\r
-    if (writeit) {\r
-       hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));\r
-       if (hres)\r
-           return hres;\r
-    }\r
-    if (!*arg) {\r
-       if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");\r
-       return S_OK;\r
-    }\r
-    disp = (DISPPARAMS*)*arg;\r
-    if (writeit) {\r
-       hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));\r
-       if (hres)\r
-           return hres;\r
-    }\r
-    if (debugout) TRACE_(olerelay)("D{");\r
-    for (i=0;i<disp->cArgs;i++) {\r
-       TYPEDESC        vtdesc;\r
-\r
-       vtdesc.vt = VT_VARIANT;\r
-       serialize_param(\r
-           tinfo,\r
-           writeit,\r
-           debugout,\r
-           dealloc,\r
-           &vtdesc,\r
-           (DWORD*)(disp->rgvarg+i),\r
-           buf\r
-        );\r
-       if (debugout && (i<disp->cArgs-1))\r
-           TRACE_(olerelay)(",");\r
-    }\r
-    if (dealloc)\r
-       HeapFree(GetProcessHeap(),0,disp->rgvarg);\r
-    if (writeit) {\r
-       hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));\r
-       if (hres)\r
-           return hres;\r
-    }\r
-    if (debugout) TRACE_(olerelay)("}{");\r
-    for (i=0;i<disp->cNamedArgs;i++) {\r
-       TYPEDESC        vtdesc;\r
-\r
-       vtdesc.vt = VT_UINT;\r
-       serialize_param(\r
-           tinfo,\r
-           writeit,\r
-           debugout,\r
-           dealloc,\r
-           &vtdesc,\r
-           (DWORD*)(disp->rgdispidNamedArgs+i),\r
-           buf\r
-       );\r
-       if (debugout && (i<disp->cNamedArgs-1))\r
-           TRACE_(olerelay)(",");\r
-    }\r
-    if (debugout) TRACE_(olerelay)("}");\r
-    if (dealloc) {\r
-       HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);\r
-       HeapFree(GetProcessHeap(),0,disp);\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-deserialize_param(\r
-    ITypeInfo          *tinfo,\r
-    BOOL               readit,\r
-    BOOL               debugout,\r
-    BOOL               alloc,\r
-    TYPEDESC           *tdesc,\r
-    DWORD              *arg,\r
-    marshal_state      *buf)\r
-{\r
-    HRESULT hres = S_OK;\r
-\r
-    TRACE("vt %d at %p\n",tdesc->vt,arg);\r
-\r
-    while (1) {\r
-       switch (tdesc->vt) {\r
-       case VT_EMPTY:\r
-           if (debugout) TRACE_(olerelay)("<empty>");\r
-           return S_OK;\r
-       case VT_NULL:\r
-           if (debugout) TRACE_(olerelay)("<null>");\r
-           return S_OK;\r
-       case VT_VARIANT: {\r
-           VARIANT     *vt = (VARIANT*)arg;\r
-\r
-           if (readit) {\r
-               DWORD   vttype;\r
-               TYPEDESC        tdesc2;\r
-               hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));\r
-               if (hres) {\r
-                   FIXME("vt type not read?\n");\r
-                   return hres;\r
-               }\r
-               memset(&tdesc2,0,sizeof(tdesc2));\r
-               tdesc2.vt = vttype;\r
-               V_VT(vt)  = vttype;\r
-               if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);\r
-               hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);\r
-               TRACE_(olerelay)(")");\r
-               return hres;\r
-           } else {\r
-               VariantInit(vt);\r
-               return S_OK;\r
-           }\r
-       }\r
-        case VT_ERROR:\r
-       case VT_BOOL:\r
-        case VT_I4:\r
-        case VT_UINT:\r
-        case VT_R4:\r
-        case VT_UI4:\r
-           if (readit) {\r
-               hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));\r
-               if (hres) ERR("Failed to read integer 4 byte\n");\r
-           }\r
-           if (debugout) TRACE_(olerelay)("%lx",*arg);\r
-           return hres;\r
-        case VT_I2:\r
-        case VT_UI2:\r
-           if (readit) {\r
-               DWORD x;\r
-               hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));\r
-               if (hres) ERR("Failed to read integer 4 byte\n");\r
-               memcpy(arg,&x,2);\r
-           }\r
-           if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff);\r
-           return hres;\r
-        case VT_I1:\r
-       case VT_UI1:\r
-           if (readit) {\r
-               DWORD x;\r
-               hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));\r
-               if (hres) ERR("Failed to read integer 4 byte\n");\r
-               memcpy(arg,&x,1);\r
-           }\r
-           if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff);\r
-           return hres;\r
-        case VT_I4|VT_BYREF:\r
-           hres = S_OK;\r
-           if (alloc)\r
-               *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));\r
-           if (readit) {\r
-               hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD));\r
-               if (hres) ERR("Failed to read integer 4 byte\n");\r
-           }\r
-           if (debugout) TRACE_(olerelay)("&0x%lx",*(DWORD*)*arg);\r
-           return hres;\r
-       case VT_BSTR|VT_BYREF: {\r
-           BSTR **bstr = (BSTR **)arg;\r
-           WCHAR       *str;\r
-           DWORD       len;\r
-\r
-           if (readit) {\r
-               hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));\r
-               if (hres) {\r
-                   ERR("failed to read bstr klen\n");\r
-                   return hres;\r
-               }\r
-               if (len == -1) {\r
-                    *bstr = CoTaskMemAlloc(sizeof(BSTR *));\r
-                   **bstr = NULL;\r
-                   if (debugout) TRACE_(olerelay)("<bstr NULL>");\r
-               } else {\r
-                   str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));\r
-                   hres = xbuf_get(buf,(LPBYTE)str,len);\r
-                   if (hres) {\r
-                       ERR("Failed to read BSTR.\n");\r
-                       return hres;\r
-                   }\r
-                    *bstr = CoTaskMemAlloc(sizeof(BSTR *));\r
-                   **bstr = SysAllocStringLen(str,len);\r
-                   if (debugout) TRACE_(olerelay)("%s",relaystr(str));\r
-                   HeapFree(GetProcessHeap(),0,str);\r
-               }\r
-           } else {\r
-               *bstr = NULL;\r
-           }\r
-           return S_OK;\r
-       }\r
-       case VT_BSTR: {\r
-           WCHAR       *str;\r
-           DWORD       len;\r
-\r
-           if (readit) {\r
-               hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));\r
-               if (hres) {\r
-                   ERR("failed to read bstr klen\n");\r
-                   return hres;\r
-               }\r
-               if (len == -1) {\r
-                   *arg = 0;\r
-                   if (debugout) TRACE_(olerelay)("<bstr NULL>");\r
-               } else {\r
-                   str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));\r
-                   hres = xbuf_get(buf,(LPBYTE)str,len);\r
-                   if (hres) {\r
-                       ERR("Failed to read BSTR.\n");\r
-                       return hres;\r
-                   }\r
-                   *arg = (DWORD)SysAllocStringLen(str,len);\r
-                   if (debugout) TRACE_(olerelay)("%s",relaystr(str));\r
-                   HeapFree(GetProcessHeap(),0,str);\r
-               }\r
-           } else {\r
-               *arg = 0;\r
-           }\r
-           return S_OK;\r
-       }\r
-       case VT_PTR: {\r
-           DWORD       cookie;\r
-           BOOL        derefhere = 0;\r
-\r
-           derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);\r
-           /* read it in all cases, we need to know if we have \r
-            * NULL pointer or not.\r
-            */\r
-           hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));\r
-           if (hres) {\r
-               ERR("Failed to load pointer cookie.\n");\r
-               return hres;\r
-           }\r
-           if (cookie != 0x42424242) {\r
-               /* we read a NULL ptr from the remote side */\r
-               if (debugout) TRACE_(olerelay)("NULL");\r
-               *arg = 0;\r
-               return S_OK;\r
-           }\r
-           if (debugout) TRACE_(olerelay)("*");\r
-           if (alloc) {\r
-               /* Allocate space for the referenced struct */\r
-               if (derefhere)\r
-                   *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));\r
-           }\r
-           if (derefhere)\r
-               return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);\r
-           else\r
-               return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);\r
-        }\r
-       case VT_UNKNOWN:\r
-           /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */\r
-           if (alloc)\r
-               *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));\r
-           hres = S_OK;\r
-           if (readit)\r
-               hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);\r
-           if (debugout)\r
-               TRACE_(olerelay)("unk(%p)",arg);\r
-           return hres;\r
-       case VT_DISPATCH:\r
-           hres = S_OK;\r
-           if (readit)\r
-               hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);\r
-           if (debugout)\r
-               TRACE_(olerelay)("idisp(%p)",arg);\r
-           return hres;\r
-       case VT_VOID:\r
-           if (debugout) TRACE_(olerelay)("<void>");\r
-           return S_OK;\r
-       case VT_USERDEFINED: {\r
-           ITypeInfo   *tinfo2;\r
-           TYPEATTR    *tattr;\r
-\r
-           hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);\r
-           if (hres) {\r
-               ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);\r
-               return hres;\r
-           }\r
-           hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);\r
-           if (hres) {\r
-               ERR("Could not get typeattr in VT_USERDEFINED.\n");\r
-           } else {\r
-               switch (tattr->typekind) {\r
-               case TKIND_DISPATCH:\r
-               case TKIND_INTERFACE:\r
-                   if (readit)\r
-                       hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);\r
-                   break;\r
-               case TKIND_RECORD: {\r
-                   int i;\r
-\r
-                   if (alloc)\r
-                       *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,tattr->cbSizeInstance);\r
-\r
-                   if (debugout) TRACE_(olerelay)("{");\r
-                   for (i=0;i<tattr->cVars;i++) {\r
-                       VARDESC *vdesc;\r
-\r
-                       hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);\r
-                       if (hres) {\r
-                           ERR("Could not get vardesc of %d\n",i);\r
-                           return hres;\r
-                       }\r
-                       hres = deserialize_param(\r
-                           tinfo2,\r
-                           readit,\r
-                           debugout,\r
-                           alloc,\r
-                           &vdesc->elemdescVar.tdesc,\r
-                           (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),\r
-                           buf\r
-                       );\r
-                       if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");\r
-                   }\r
-                   if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))\r
-                       memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));\r
-                   if (debugout) TRACE_(olerelay)("}");\r
-                   break;\r
-               }\r
-               default:\r
-                   ERR("Unhandled typekind %d\n",tattr->typekind);\r
-                   hres = E_FAIL;\r
-                   break;\r
-               }\r
-           }\r
-           if (hres)\r
-               ERR("failed to stuballoc in TKIND_RECORD.\n");\r
-           ITypeInfo_Release(tinfo2);\r
-           return hres;\r
-       }\r
-       case VT_CARRAY: {\r
-           /* arg is pointing to the start of the array. */\r
-           ARRAYDESC *adesc = tdesc->u.lpadesc;\r
-           int         arrsize,i;\r
-           arrsize = 1;\r
-           if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");\r
-           for (i=0;i<adesc->cDims;i++)\r
-               arrsize *= adesc->rgbounds[i].cElements;\r
-           for (i=0;i<arrsize;i++)\r
-               deserialize_param(\r
-                   tinfo,\r
-                   readit,\r
-                   debugout,\r
-                   alloc,\r
-                   &adesc->tdescElem,\r
-                   (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),\r
-                   buf\r
-               );\r
-           return S_OK;\r
-       }\r
-       default:\r
-           ERR("No handler for VT type %d!\n",tdesc->vt);\r
-           return S_OK;\r
-       }\r
-    }\r
-}\r
-\r
-static HRESULT\r
-deserialize_LPVOID_ptr(\r
-    ITypeInfo          *tinfo,\r
-    BOOL               readit,\r
-    BOOL               debugout,\r
-    BOOL               alloc,\r
-    TYPEDESC           *tdesc,\r
-    DWORD              *arg,\r
-    marshal_state      *buf\r
-) {\r
-    HRESULT    hres;\r
-    DWORD      cookie;\r
-\r
-    if ((tdesc->vt != VT_PTR)                  ||\r
-       (tdesc->u.lptdesc->vt != VT_PTR)        ||\r
-       (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)\r
-    ) {\r
-       FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");\r
-       return E_FAIL;\r
-    }\r
-    if (alloc)\r
-       *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));\r
-    if (readit) {\r
-       hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));\r
-       if (hres)\r
-           return hres;\r
-       if (cookie != 0x42424242) {\r
-           *(DWORD*)*arg = 0;\r
-           if (debugout) TRACE_(olerelay)("<lpvoid NULL>");\r
-           return S_OK;\r
-       }\r
-    }\r
-    if (readit) {\r
-       hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);\r
-       if (hres) {\r
-           FIXME("_unmarshal_interface of %s , %p failed with %lx\n", debugstr_guid(&buf->iid), (LPUNKNOWN*)*arg, hres);\r
-           return hres;\r
-       }\r
-    }\r
-    if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg);\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT\r
-deserialize_DISPPARAM_ptr(\r
-    ITypeInfo          *tinfo,\r
-    BOOL               readit,\r
-    BOOL               debugout,\r
-    BOOL               alloc,\r
-    TYPEDESC           *tdesc,\r
-    DWORD              *arg,\r
-    marshal_state      *buf)\r
-{\r
-    DWORD      cookie;\r
-    DISPPARAMS *disps;\r
-    HRESULT    hres;\r
-    int                i;\r
-\r
-    if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {\r
-       FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");\r
-       return E_FAIL;\r
-    }\r
-    if (readit) {\r
-       hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));\r
-       if (hres)\r
-           return hres;\r
-       if (cookie == 0) {\r
-           *arg = 0;\r
-           if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");\r
-           return S_OK;\r
-       }\r
-    }\r
-    if (alloc)\r
-       *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));\r
-    disps = (DISPPARAMS*)*arg;\r
-    if (!readit)\r
-       return S_OK;\r
-    hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));\r
-    if (hres)\r
-       return hres;\r
-    if (alloc)\r
-        disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);\r
-    if (debugout) TRACE_(olerelay)("D{");\r
-    for (i=0; i< disps->cArgs; i++) {\r
-        TYPEDESC vdesc;\r
-\r
-       vdesc.vt = VT_VARIANT;\r
-       hres = deserialize_param(\r
-           tinfo,\r
-           readit,\r
-           debugout,\r
-           alloc,\r
-           &vdesc,\r
-           (DWORD*)(disps->rgvarg+i),\r
-           buf\r
-       );\r
-    }\r
-    if (debugout) TRACE_(olerelay)("}{");\r
-    hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));\r
-    if (hres)\r
-       return hres;\r
-    if (disps->cNamedArgs) {\r
-       if (alloc)\r
-           disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);\r
-       for (i=0; i< disps->cNamedArgs; i++) {\r
-           TYPEDESC vdesc;\r
-\r
-           vdesc.vt = VT_UINT;\r
-           hres = deserialize_param(\r
-               tinfo,\r
-               readit,\r
-               debugout,\r
-               alloc,\r
-               &vdesc,\r
-               (DWORD*)(disps->rgdispidNamedArgs+i),\r
-               buf\r
-           );\r
-           if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(",");\r
-       }\r
-    }\r
-    if (debugout) TRACE_(olerelay)("}");\r
-    return S_OK;\r
-}\r
-\r
-/* Searches function, also in inherited interfaces */\r
-static HRESULT\r
-_get_funcdesc(\r
-    ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname)\r
-{\r
-    int i = 0, j = 0;\r
-    HRESULT hres;\r
-\r
-    if (fname) *fname = NULL;\r
-    if (iname) *iname = NULL;\r
-\r
-    while (1) {\r
-       hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);\r
-       if (hres) {\r
-           ITypeInfo   *tinfo2;\r
-           HREFTYPE    href;\r
-           TYPEATTR    *attr;\r
-\r
-           hres = ITypeInfo_GetTypeAttr(tinfo, &attr);\r
-           if (hres) {\r
-               ERR("GetTypeAttr failed with %lx\n",hres);\r
-               return hres;\r
-           }\r
-           /* Not found, so look in inherited ifaces. */\r
-           for (j=0;j<attr->cImplTypes;j++) {\r
-               hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);\r
-               if (hres) {\r
-                   ERR("Did not find a reftype for interface offset %d?\n",j);\r
-                   break;\r
-               }\r
-               hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);\r
-               if (hres) {\r
-                   ERR("Did not find a typeinfo for reftype %ld?\n",href);\r
-                   continue;\r
-               }\r
-               hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);\r
-               ITypeInfo_Release(tinfo2);\r
-               if (!hres) return S_OK;\r
-           }\r
-           return hres;\r
-       }\r
-       if (((*fdesc)->oVft/4) == iMethod) {\r
-           if (fname)\r
-               ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);\r
-           if (iname)\r
-               ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);\r
-           return S_OK;\r
-       }\r
-       i++;\r
-    }\r
-}\r
-\r
-static DWORD\r
-xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)\r
-{\r
-    DWORD              *args = ((DWORD*)&tpinfo)+1, *xargs;\r
-    FUNCDESC           *fdesc;\r
-    HRESULT            hres;\r
-    int                        i, relaydeb = TRACE_ON(olerelay);\r
-    marshal_state      buf;\r
-    RPCOLEMESSAGE      msg;\r
-    ULONG              status;\r
-    BSTR               fname,iname;\r
-    BSTR               names[10];\r
-    int                        nrofnames;\r
-    int                        is_idispatch_getidsofnames = 0;\r
-    DWORD              remoteresult = 0;\r
-\r
-    EnterCriticalSection(&tpinfo->crit);\r
-\r
-    hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);\r
-    if (hres) {\r
-       ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);\r
-        LeaveCriticalSection(&tpinfo->crit);\r
-       return E_FAIL;\r
-    }\r
-\r
-    if (!tpinfo->chanbuf)\r
-    {\r
-        WARN("Tried to use disconnected proxy\n");\r
-        LeaveCriticalSection(&tpinfo->crit);\r
-        return RPC_E_DISCONNECTED;\r
-    }\r
-\r
-    if (relaydeb) {\r
-       TRACE_(olerelay)("->");\r
-       if (iname)\r
-           TRACE_(olerelay)("%s:",relaystr(iname));\r
-       if (fname)\r
-           TRACE_(olerelay)("%s(%d)",relaystr(fname),method);\r
-       else\r
-           TRACE_(olerelay)("%d",method);\r
-       TRACE_(olerelay)("(");\r
-    }\r
-    if (iname && fname && !lstrcmpW(iname,IDispatchW) && !lstrcmpW(fname,GetIDsOfNamesW))\r
-        is_idispatch_getidsofnames = 1;\r
-\r
-    if (iname) SysFreeString(iname);\r
-    if (fname) SysFreeString(fname);\r
-\r
-    memset(&buf,0,sizeof(buf));\r
-    buf.iid = IID_IUnknown;\r
-\r
-    /* Special IDispatch::GetIDsOfNames() serializer */\r
-    if (is_idispatch_getidsofnames) {\r
-       hres = serialize_IDispatch_GetIDsOfNames(TRUE,relaydeb,args,&buf);\r
-       if (hres != S_OK) {\r
-           FIXME("serialize of IDispatch::GetIDsOfNames failed!\n");\r
-           return hres;\r
-       }\r
-       goto afterserialize;\r
-    }\r
-\r
-    /* special QueryInterface serialize */\r
-    if (method == 0) {\r
-       xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));\r
-       if (relaydeb) TRACE_(olerelay)("riid=%s,[out])",debugstr_guid((REFIID)args[0]));\r
-       goto afterserialize;\r
-    }\r
-\r
-    /* normal typelib driven serializing */\r
-\r
-    /* Need them for hack below */\r
-    memset(names,0,sizeof(names));\r
-    if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))\r
-       nrofnames = 0;\r
-    if (nrofnames > sizeof(names)/sizeof(names[0]))\r
-       ERR("Need more names!\n");\r
-\r
-    xargs = args;\r
-    for (i=0;i<fdesc->cParams;i++) {\r
-       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;\r
-       BOOL    isserialized = FALSE;\r
-       if (relaydeb) {\r
-           if (i) TRACE_(olerelay)(",");\r
-           if (i+1<nrofnames && names[i+1])\r
-               TRACE_(olerelay)("%s=",relaystr(names[i+1]));\r
-       }\r
-       /* No need to marshal other data than FIN and any VT_PTR. */\r
-       if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) && (elem->tdesc.vt != VT_PTR)) {\r
-           xargs+=_argsize(elem->tdesc.vt);\r
-           if (relaydeb) TRACE_(olerelay)("[out]");\r
-           continue;\r
-       }\r
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {\r
-           /* If the parameter is 'riid', we use it as interface IID\r
-            * for a later ppvObject serialization.\r
-            */\r
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);\r
-\r
-           /* DISPPARAMS* needs special serializer */\r
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {\r
-               hres = serialize_DISPPARAM_ptr(\r
-                   tpinfo->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,\r
-                   relaydeb,\r
-                   FALSE,\r
-                   &elem->tdesc,\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               isserialized = TRUE;\r
-           }\r
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {\r
-               hres = serialize_LPVOID_ptr(\r
-                   tpinfo->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,\r
-                   relaydeb,\r
-                   FALSE,\r
-                   &elem->tdesc,\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               if (hres == S_OK)\r
-                   isserialized = TRUE;\r
-           }\r
-       }\r
-       if (!isserialized)\r
-           hres = serialize_param(\r
-               tpinfo->tinfo,\r
-               elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,\r
-               relaydeb,\r
-               FALSE,\r
-               &elem->tdesc,\r
-               xargs,\r
-               &buf\r
-           );\r
-\r
-       if (hres) {\r
-           ERR("Failed to serialize param, hres %lx\n",hres);\r
-           break;\r
-       }\r
-       xargs+=_argsize(elem->tdesc.vt);\r
-    }\r
-    if (relaydeb) TRACE_(olerelay)(")");\r
-\r
-afterserialize:\r
-    memset(&msg,0,sizeof(msg));\r
-    msg.cbBuffer = buf.curoff;\r
-    msg.iMethod  = method;\r
-    hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));\r
-    if (hres) {\r
-       ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);\r
-        LeaveCriticalSection(&tpinfo->crit);\r
-       return hres;\r
-    }\r
-    memcpy(msg.Buffer,buf.base,buf.curoff);\r
-    if (relaydeb) TRACE_(olerelay)("\n");\r
-    hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);\r
-    if (hres) {\r
-       ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);\r
-        LeaveCriticalSection(&tpinfo->crit);\r
-       return hres;\r
-    }\r
-\r
-    if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status);\r
-    if (buf.base)\r
-       buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);\r
-    else\r
-       buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);\r
-    buf.size = msg.cbBuffer;\r
-    memcpy(buf.base,msg.Buffer,buf.size);\r
-    buf.curoff = 0;\r
-\r
-    /* Special IDispatch::GetIDsOfNames() deserializer */\r
-    if (is_idispatch_getidsofnames) {\r
-       hres = deserialize_IDispatch_GetIDsOfNames(FALSE,relaydeb,args,&buf);\r
-       if (hres != S_OK) {\r
-           FIXME("deserialize of IDispatch::GetIDsOfNames failed!\n");\r
-           return hres;\r
-       }\r
-       goto after_deserialize;\r
-    }\r
-    /* Special QueryInterface deserializer */\r
-    if (method == 0) {\r
-       _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);\r
-       if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1]));\r
-       goto after_deserialize;\r
-    }\r
-\r
-    /* generic deserializer using typelib description */\r
-    xargs = args;\r
-    status = S_OK;\r
-    for (i=0;i<fdesc->cParams;i++) {\r
-       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;\r
-       BOOL    isdeserialized = FALSE;\r
-\r
-       if (relaydeb) {\r
-           if (i) TRACE_(olerelay)(",");\r
-           if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));\r
-       }\r
-       /* No need to marshal other data than FOUT and any VT_PTR */\r
-       if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) && (elem->tdesc.vt != VT_PTR)) {\r
-           xargs += _argsize(elem->tdesc.vt);\r
-           if (relaydeb) TRACE_(olerelay)("[in]");\r
-           continue;\r
-       }\r
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {\r
-           /* If the parameter is 'riid', we use it as interface IID\r
-            * for a later ppvObject serialization.\r
-            */\r
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);\r
-\r
-           /* deserialize DISPPARAM */\r
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {\r
-               hres = deserialize_DISPPARAM_ptr(\r
-                   tpinfo->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,\r
-                   relaydeb,\r
-                   FALSE,\r
-                   &(elem->tdesc),\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               if (hres) {\r
-                   ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);\r
-                   break;\r
-               }\r
-               isdeserialized = TRUE;\r
-           }\r
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {\r
-               hres = deserialize_LPVOID_ptr(\r
-                   tpinfo->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,\r
-                   relaydeb,\r
-                   FALSE,\r
-                   &elem->tdesc,\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               if (hres == S_OK)\r
-                   isdeserialized = TRUE;\r
-           }\r
-       }\r
-       if (!isdeserialized)\r
-           hres = deserialize_param(\r
-               tpinfo->tinfo,\r
-               elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,\r
-               relaydeb,\r
-               FALSE,\r
-               &(elem->tdesc),\r
-               xargs,\r
-               &buf\r
-           );\r
-       if (hres) {\r
-           ERR("Failed to unmarshall param, hres %lx\n",hres);\r
-           status = hres;\r
-           break;\r
-       }\r
-       xargs += _argsize(elem->tdesc.vt);\r
-    }\r
-after_deserialize:\r
-    hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));\r
-    if (hres != S_OK)\r
-       return hres;\r
-    if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult);\r
-\r
-    if (status != S_OK) /* OLE/COM internal error */\r
-       return status;\r
-\r
-    HeapFree(GetProcessHeap(),0,buf.base);\r
-    LeaveCriticalSection(&tpinfo->crit);\r
-    return remoteresult;\r
-}\r
-\r
-HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)\r
-{\r
-    TMProxyImpl *proxy = (TMProxyImpl *)iface;\r
-\r
-    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);\r
-\r
-    if (proxy->outerunknown)\r
-        return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);\r
-\r
-    FIXME("No interface\n");\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)\r
-{\r
-    TMProxyImpl *proxy = (TMProxyImpl *)iface;\r
-\r
-    TRACE("\n");\r
-\r
-    if (proxy->outerunknown)\r
-        return IUnknown_AddRef(proxy->outerunknown);\r
-\r
-    return 2; /* FIXME */\r
-}\r
-\r
-ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)\r
-{\r
-    TMProxyImpl *proxy = (TMProxyImpl *)iface;\r
-\r
-    TRACE("\n");\r
-\r
-    if (proxy->outerunknown)\r
-        return IUnknown_Release(proxy->outerunknown);\r
-\r
-    return 1; /* FIXME */\r
-}\r
-\r
-static HRESULT WINAPI\r
-PSFacBuf_CreateProxy(\r
-    LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,\r
-    IRpcProxyBuffer **ppProxy, LPVOID *ppv)\r
-{\r
-    HRESULT    hres;\r
-    ITypeInfo  *tinfo;\r
-    int                i, nroffuncs;\r
-    FUNCDESC   *fdesc;\r
-    TMProxyImpl        *proxy;\r
-\r
-    TRACE("(...%s...)\n",debugstr_guid(riid));\r
-    hres = _get_typeinfo_for_iid(riid,&tinfo);\r
-    if (hres) {\r
-       ERR("No typeinfo for %s?\n",debugstr_guid(riid));\r
-       return hres;\r
-    }\r
-    nroffuncs = _nroffuncs(tinfo);\r
-    proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));\r
-    if (!proxy) return E_OUTOFMEMORY;\r
-\r
-    assert(sizeof(TMAsmProxy) == 12);\r
-\r
-    proxy->outerunknown = pUnkOuter;\r
-    proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
-    if (!proxy->asmstubs) {\r
-        ERR("Could not commit pages for proxy thunks\n");\r
-        CoTaskMemFree(proxy);\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    InitializeCriticalSection(&proxy->crit);\r
-\r
-    proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);\r
-    for (i=0;i<nroffuncs;i++) {\r
-       TMAsmProxy      *xasm = proxy->asmstubs+i;\r
-\r
-       switch (i) {\r
-       case 0:\r
-               proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;\r
-               break;\r
-       case 1:\r
-               proxy->lpvtbl[i] = ProxyIUnknown_AddRef;\r
-               break;\r
-       case 2:\r
-               proxy->lpvtbl[i] = ProxyIUnknown_Release;\r
-               break;\r
-       default: {\r
-               int j;\r
-               /* nrofargs without This */\r
-               int nrofargs;\r
-               hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);\r
-               if (hres) {\r
-                   ERR("GetFuncDesc %lx should not fail here.\n",hres);\r
-                   return hres;\r
-               }\r
-               /* some args take more than 4 byte on the stack */\r
-               nrofargs = 0;\r
-               for (j=0;j<fdesc->cParams;j++)\r
-                   nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);\r
-\r
-               if (fdesc->callconv != CC_STDCALL) {\r
-                   ERR("calling convention is not stdcall????\n");\r
-                   return E_FAIL;\r
-               }\r
-/* popl %eax   -       return ptr\r
- * pushl <nr>\r
- * pushl %eax\r
- * call xCall\r
- * lret <nr> (+4)\r
- *\r
- *\r
- * arg3 arg2 arg1 <method> <returnptr>\r
- */\r
-               xasm->popleax   = 0x58;\r
-               xasm->pushlval  = 0x6a;\r
-               xasm->nr        = i;\r
-               xasm->pushleax  = 0x50;\r
-               xasm->lcall     = 0xe8; /* relative jump */\r
-               xasm->xcall     = (DWORD)xCall;\r
-               xasm->xcall     -= (DWORD)&(xasm->lret);\r
-               xasm->lret      = 0xc2;\r
-               xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */\r
-               proxy->lpvtbl[i] = xasm;\r
-               break;\r
-           }\r
-       }\r
-    }\r
-    proxy->lpvtbl2     = &tmproxyvtable;\r
-    /* 1 reference for the proxy and 1 for the object */\r
-    proxy->ref         = 2;\r
-    proxy->tinfo       = tinfo;\r
-    memcpy(&proxy->iid,riid,sizeof(*riid));\r
-    proxy->chanbuf      = 0;\r
-    *ppv               = (LPVOID)proxy;\r
-    *ppProxy           = (IRpcProxyBuffer *)&(proxy->lpvtbl2);\r
-    return S_OK;\r
-}\r
-\r
-typedef struct _TMStubImpl {\r
-    IRpcStubBufferVtbl *lpvtbl;\r
-    ULONG                      ref;\r
-\r
-    LPUNKNOWN                  pUnk;\r
-    ITypeInfo                  *tinfo;\r
-    IID                                iid;\r
-} TMStubImpl;\r
-\r
-static HRESULT WINAPI\r
-TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)\r
-{\r
-    if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){\r
-       *ppv = (LPVOID)iface;\r
-       IRpcStubBuffer_AddRef(iface);\r
-       return S_OK;\r
-    }\r
-    FIXME("%s, not supported IID.\n",debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI\r
-TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)\r
-{\r
-    TMStubImpl *This = (TMStubImpl *)iface;\r
-    ULONG refCount = InterlockedIncrement(&This->ref);\r
-        \r
-    TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);\r
-\r
-    return refCount;\r
-}\r
-\r
-static ULONG WINAPI\r
-TMStubImpl_Release(LPRPCSTUBBUFFER iface)\r
-{\r
-    TMStubImpl *This = (TMStubImpl *)iface;\r
-    ULONG refCount = InterlockedDecrement(&This->ref);\r
-\r
-    TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);\r
-\r
-    if (!refCount)\r
-    {\r
-        IRpcStubBuffer_Disconnect(iface);\r
-        CoTaskMemFree(This);\r
-    }\r
-    return refCount;\r
-}\r
-\r
-static HRESULT WINAPI\r
-TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)\r
-{\r
-    TMStubImpl *This = (TMStubImpl *)iface;\r
-\r
-    TRACE("(%p)->(%p)\n", This, pUnkServer);\r
-\r
-    IUnknown_AddRef(pUnkServer);\r
-    This->pUnk = pUnkServer;\r
-    return S_OK;\r
-}\r
-\r
-static void WINAPI\r
-TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)\r
-{\r
-    TMStubImpl *This = (TMStubImpl *)iface;\r
-\r
-    TRACE("(%p)->()\n", This);\r
-\r
-    IUnknown_Release(This->pUnk);\r
-    This->pUnk = NULL;\r
-    return;\r
-}\r
-\r
-static HRESULT WINAPI\r
-TMStubImpl_Invoke(\r
-    LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)\r
-{\r
-    int                i;\r
-    FUNCDESC   *fdesc;\r
-    TMStubImpl *This = (TMStubImpl *)iface;\r
-    HRESULT    hres;\r
-    DWORD      *args, res, *xargs, nrofargs;\r
-    marshal_state      buf;\r
-    int                nrofnames;\r
-    BSTR       names[10];\r
-    BSTR       fname = NULL,iname = NULL;\r
-    BOOL       is_idispatch_getidsofnames = 0;\r
-\r
-    memset(&buf,0,sizeof(buf));\r
-    buf.size   = xmsg->cbBuffer;\r
-    buf.base   = xmsg->Buffer;\r
-    buf.curoff = 0;\r
-    buf.iid    = IID_IUnknown;\r
-\r
-    TRACE("...\n");\r
-    if (xmsg->iMethod == 0) { /* QI */\r
-       IID             xiid;\r
-       /* in: IID, out: <iface> */\r
-\r
-       xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));\r
-       buf.curoff = 0;\r
-       hres = _marshal_interface(&buf,&xiid,This->pUnk);\r
-       xmsg->Buffer    = buf.base; /* Might have been reallocated */\r
-       xmsg->cbBuffer  = buf.size;\r
-       return hres;\r
-    }\r
-    hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,&iname,&fname);\r
-    if (hres) {\r
-       ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);\r
-       return hres;\r
-    }\r
-\r
-    if (iname && fname && !lstrcmpW(iname, IDispatchW) && !lstrcmpW(fname, GetIDsOfNamesW))\r
-       is_idispatch_getidsofnames = 1;\r
-\r
-    if (iname) SysFreeString (iname);\r
-    if (fname) SysFreeString (fname);\r
-\r
-    /* Need them for hack below */\r
-    memset(names,0,sizeof(names));\r
-    ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);\r
-    if (nrofnames > sizeof(names)/sizeof(names[0])) {\r
-       ERR("Need more names!\n");\r
-    }\r
-\r
-    /*dump_FUNCDESC(fdesc);*/\r
-    nrofargs = 0;\r
-    for (i=0;i<fdesc->cParams;i++)\r
-       nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);\r
-    args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));\r
-    if (!args) return E_OUTOFMEMORY;\r
-\r
-    if (is_idispatch_getidsofnames) {\r
-       hres = deserialize_IDispatch_GetIDsOfNames(TRUE,FALSE,args+1,&buf);\r
-       if (hres != S_OK) {\r
-           FIXME("deserialize_IDispatch_GetIDsOfNames failed!\n");\r
-           return hres;\r
-       }\r
-       xargs = args+1+5;\r
-       goto afterdeserialize;\r
-    }\r
-\r
-    /* Allocate all stuff used by call. */\r
-    xargs = args+1;\r
-    for (i=0;i<fdesc->cParams;i++) {\r
-       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;\r
-       BOOL            isdeserialized = FALSE;\r
-\r
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {\r
-           /* If the parameter is 'riid', we use it as interface IID\r
-            * for a later ppvObject serialization.\r
-            */\r
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);\r
-\r
-           /* deserialize DISPPARAM */\r
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {\r
-               hres = deserialize_DISPPARAM_ptr(\r
-                   This->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,\r
-                   FALSE,\r
-                   TRUE,\r
-                   &(elem->tdesc),\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               if (hres) {\r
-                   ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);\r
-                   break;\r
-               }\r
-               isdeserialized = TRUE;\r
-           }\r
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {\r
-               hres = deserialize_LPVOID_ptr(\r
-                   This->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,\r
-                   FALSE,\r
-                   TRUE,\r
-                   &elem->tdesc,\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               if (hres == S_OK)\r
-                   isdeserialized = TRUE;\r
-           }\r
-       }\r
-       if (!isdeserialized)\r
-           hres = deserialize_param(\r
-               This->tinfo,\r
-               elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,\r
-               FALSE,\r
-               TRUE,\r
-               &(elem->tdesc),\r
-               xargs,\r
-               &buf\r
-           );\r
-       xargs += _argsize(elem->tdesc.vt);\r
-       if (hres) {\r
-           ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);\r
-           break;\r
-       }\r
-    }\r
-afterdeserialize:\r
-    hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));\r
-    if (hres) {\r
-       ERR("Does not support iface %s, returning %lx\n",debugstr_guid(&(This->iid)), hres);\r
-       return hres;\r
-    }\r
-    res = _invoke(\r
-       (*((FARPROC**)args[0]))[fdesc->oVft/4],\r
-       fdesc->callconv,\r
-       (xargs-args),\r
-       args\r
-    );\r
-    IUnknown_Release((LPUNKNOWN)args[0]);\r
-    buf.curoff = 0;\r
-\r
-    /* special IDispatch::GetIDsOfNames serializer */\r
-    if (is_idispatch_getidsofnames) {\r
-       hres = serialize_IDispatch_GetIDsOfNames(FALSE,FALSE,args+1,&buf);\r
-       if (hres != S_OK) {\r
-           FIXME("serialize of IDispatch::GetIDsOfNames failed!\n");\r
-           return hres;\r
-       }\r
-       goto afterserialize;\r
-    }\r
-    xargs = args+1;\r
-    for (i=0;i<fdesc->cParams;i++) {\r
-       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;\r
-       BOOL            isserialized = FALSE;\r
-\r
-       if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {\r
-           /* If the parameter is 'riid', we use it as interface IID\r
-            * for a later ppvObject serialization.\r
-            */\r
-           buf.thisisiid = !lstrcmpW(names[i+1],riidW);\r
-\r
-           /* DISPPARAMS* needs special serializer */\r
-           if (!lstrcmpW(names[i+1],pdispparamsW)) {\r
-               hres = serialize_DISPPARAM_ptr(\r
-                   This->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,\r
-                   FALSE,\r
-                   TRUE,\r
-                   &elem->tdesc,\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               isserialized = TRUE;\r
-           }\r
-           if (!lstrcmpW(names[i+1],ppvObjectW)) {\r
-               hres = serialize_LPVOID_ptr(\r
-                   This->tinfo,\r
-                   elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,\r
-                   FALSE,\r
-                   TRUE,\r
-                   &elem->tdesc,\r
-                   xargs,\r
-                   &buf\r
-               );\r
-               if (hres == S_OK)\r
-                   isserialized = TRUE;\r
-           }\r
-       }\r
-       if (!isserialized)\r
-           hres = serialize_param(\r
-              This->tinfo,\r
-              elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,\r
-              FALSE,\r
-              TRUE,\r
-              &elem->tdesc,\r
-              xargs,\r
-              &buf\r
-           );\r
-       xargs += _argsize(elem->tdesc.vt);\r
-       if (hres) {\r
-           ERR("Failed to stuballoc param, hres %lx\n",hres);\r
-           break;\r
-       }\r
-    }\r
-afterserialize:\r
-    hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));\r
-    if (hres != S_OK)\r
-       return hres;\r
-   \r
-    /* might need to use IRpcChannelBuffer_GetBuffer ? */\r
-    xmsg->cbBuffer     = buf.curoff;\r
-    xmsg->Buffer       = buf.base;\r
-    HeapFree(GetProcessHeap(),0,args);\r
-    return S_OK;\r
-}\r
-\r
-static LPRPCSTUBBUFFER WINAPI\r
-TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {\r
-    FIXME("Huh (%s)?\n",debugstr_guid(riid));\r
-    return NULL;\r
-}\r
-\r
-static ULONG WINAPI\r
-TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {\r
-    TMStubImpl *This = (TMStubImpl *)iface;\r
-\r
-    return This->ref; /*FIXME? */\r
-}\r
-\r
-static HRESULT WINAPI\r
-TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {\r
-    return E_NOTIMPL;\r
-}\r
-\r
-static void WINAPI\r
-TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {\r
-    return;\r
-}\r
-\r
-IRpcStubBufferVtbl tmstubvtbl = {\r
-    TMStubImpl_QueryInterface,\r
-    TMStubImpl_AddRef,\r
-    TMStubImpl_Release,\r
-    TMStubImpl_Connect,\r
-    TMStubImpl_Disconnect,\r
-    TMStubImpl_Invoke,\r
-    TMStubImpl_IsIIDSupported,\r
-    TMStubImpl_CountRefs,\r
-    TMStubImpl_DebugServerQueryInterface,\r
-    TMStubImpl_DebugServerRelease\r
-};\r
-\r
-static HRESULT WINAPI\r
-PSFacBuf_CreateStub(\r
-    LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,\r
-    IRpcStubBuffer** ppStub\r
-) {\r
-    HRESULT hres;\r
-    ITypeInfo  *tinfo;\r
-    TMStubImpl *stub;\r
-\r
-    TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);\r
-    hres = _get_typeinfo_for_iid(riid,&tinfo);\r
-    if (hres) {\r
-       ERR("No typeinfo for %s?\n",debugstr_guid(riid));\r
-       return hres;\r
-    }\r
-    stub = CoTaskMemAlloc(sizeof(TMStubImpl));\r
-    if (!stub)\r
-       return E_OUTOFMEMORY;\r
-    stub->lpvtbl       = &tmstubvtbl;\r
-    stub->ref          = 1;\r
-    stub->tinfo                = tinfo;\r
-    memcpy(&(stub->iid),riid,sizeof(*riid));\r
-    hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);\r
-    *ppStub            = (LPRPCSTUBBUFFER)stub;\r
-    TRACE("IRpcStubBuffer: %p\n", stub);\r
-    if (hres)\r
-       ERR("Connect to pUnkServer failed?\n");\r
-    return hres;\r
-}\r
-\r
-static IPSFactoryBufferVtbl psfacbufvtbl = {\r
-    PSFacBuf_QueryInterface,\r
-    PSFacBuf_AddRef,\r
-    PSFacBuf_Release,\r
-    PSFacBuf_CreateProxy,\r
-    PSFacBuf_CreateStub\r
-};\r
-\r
-/* This is the whole PSFactoryBuffer object, just the vtableptr */\r
-static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;\r
-\r
-/***********************************************************************\r
- *           DllGetClassObject [OLE32.63]\r
- */\r
-HRESULT WINAPI\r
-TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)\r
-{\r
-    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {\r
-       *ppv = &lppsfac;\r
-       return S_OK;\r
-    }\r
-    return E_NOINTERFACE;\r
-}\r
+/*
+ *     TYPELIB Marshaler
+ *
+ *     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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "winerror.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "winuser.h"
+
+#include "ole2.h"
+#include "typelib.h"
+#include "wine/debug.h"
+
+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;
+} 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) {
+       if (buf->base) {
+           buf->size += 100;
+           buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
+           if (!buf->base)
+               return E_OUTOFMEMORY;
+       } else {
+           buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
+           buf->size = 32;
+           if (!buf->base)
+               return E_OUTOFMEMORY;
+       }
+    }
+    memcpy(buf->base+buf->curoff,stuff,size);
+    buf->curoff += size;
+    return S_OK;
+}
+
+static HRESULT
+xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
+    if (buf->size < buf->curoff+size) return E_FAIL;
+    memcpy(stuff,buf->base+buf->curoff,size);
+    buf->curoff += size;
+    return S_OK;
+}
+
+static HRESULT
+xbuf_skip(marshal_state *buf, DWORD size) {
+    if (buf->size < buf->curoff+size) return E_FAIL;
+    buf->curoff += size;
+    return S_OK;
+}
+
+static HRESULT
+_unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
+    IStream            *pStm;
+    ULARGE_INTEGER     newpos;
+    LARGE_INTEGER      seekto;
+    ULONG              res;
+    HRESULT            hres;
+    DWORD              xsize;
+
+    TRACE("...%s...\n",debugstr_guid(riid));
+    
+    *pUnk = NULL;
+    hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
+    if (hres) {
+        ERR("xbuf_get failed\n");
+        return hres;
+    }
+    
+    if (xsize == 0) return S_OK;
+    
+    hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
+    if (hres) {
+       ERR("Stream create failed %lx\n",hres);
+       return hres;
+    }
+    
+    hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
+    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) {
+        ERR("Failed Seek %lx\n",hres);
+        return hres;
+    }
+    
+    hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
+    if (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) {
+    LPBYTE             tempbuf = NULL;
+    IStream            *pStm = NULL;
+    STATSTG            ststg;
+    ULARGE_INTEGER     newpos;
+    LARGE_INTEGER      seekto;
+    ULONG              res;
+    DWORD              xsize;
+    HRESULT            hres;
+
+    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 = CreateStreamOnHGlobal(0,TRUE,&pStm);
+    if (hres) {
+       ERR("Stream create failed %lx\n",hres);
+       goto fail;
+    }
+    
+    hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
+    if (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) {
+        ERR("Failed Seek %lx\n",hres);
+        goto fail;
+    }
+    
+    hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
+    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;
+}
+
+/********************* OLE Proxy/Stub Factory ********************************/
+static HRESULT WINAPI
+PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
+    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
+       *ppv = (LPVOID)iface;
+       /* No ref counting, static class */
+       return S_OK;
+    }
+    FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
+static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
+
+static HRESULT
+_get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
+    HRESULT    hres;
+    HKEY       ikey;
+    char       tlguid[200],typelibkey[300],interfacekey[300],ver[100];
+    char       tlfn[260];
+    OLECHAR    tlfnW[260];
+    DWORD      tlguidlen, verlen, type;
+    LONG       tlfnlen;
+    ITypeLib   *tl;
+
+    sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
+       riid->Data1, riid->Data2, riid->Data3,
+       riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
+       riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
+    );
+
+    if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
+       ERR("No %s key found.\n",interfacekey);
+               return E_FAIL;
+    }
+    type = (1<<REG_SZ);
+    tlguidlen = sizeof(tlguid);
+    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,(LPBYTE)ver,&verlen)) {
+       ERR("Could not get version value?\n");
+       RegCloseKey(ikey);
+       return E_FAIL;
+    }
+    RegCloseKey(ikey);
+    sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
+    tlfnlen = sizeof(tlfn);
+    if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
+       ERR("Could not get typelib fn?\n");
+       return E_FAIL;
+    }
+    MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
+    hres = LoadTypeLib(tlfnW,&tl);
+    if (hres) {
+       ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
+       return hres;
+    }
+    hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
+    if (hres) {
+       ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
+       ITypeLib_Release(tl);
+       return hres;
+    }
+    /* FIXME: do this?  ITypeLib_Release(tl); */
+    return hres;
+}
+
+/* Determine nr of functions. Since we use the toplevel interface and all
+ * inherited ones have lower numbers, we are ok to not to descent into
+ * the inheritance tree I think.
+ */
+static int _nroffuncs(ITypeInfo *tinfo) {
+    int        n, max = 0;
+    const FUNCDESC *fdesc;
+    HRESULT    hres;
+
+    n=0;
+    while (1) {
+       hres = ITypeInfoImpl_GetInternalFuncDesc(tinfo,n,&fdesc);
+       if (hres)
+           return max+1;
+       if (fdesc->oVft/4 > max)
+           max = fdesc->oVft/4;
+       n++;
+    }
+    /*NOTREACHED*/
+}
+
+#ifdef __i386__
+
+#include "pshpack1.h"
+
+typedef struct _TMAsmProxy {
+    BYTE       popleax;
+    BYTE       pushlval;
+    BYTE       nr;
+    BYTE       pushleax;
+    BYTE       lcall;
+    DWORD      xcall;
+    BYTE       lret;
+    WORD       bytestopop;
+} TMAsmProxy;
+
+#include "poppack.h"
+
+#else /* __i386__ */
+# warning You need to implement stubless proxies for your architecture
+typedef struct _TMAsmProxy {
+} TMAsmProxy;
+#endif
+
+typedef struct _TMProxyImpl {
+    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)
+{
+    TRACE("()\n");
+    if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
+        *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)
+{
+    ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
+    ULONG refCount = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);
+
+    return refCount;
+}
+
+static ULONG WINAPI
+TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
+{
+    ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
+    ULONG refCount = InterlockedDecrement(&This->ref);
+
+    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);
+
+    TRACE("(%p)\n", pRpcChannelBuffer);
+
+    EnterCriticalSection(&This->crit);
+
+    IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
+    This->chanbuf = pRpcChannelBuffer;
+
+    LeaveCriticalSection(&This->crit);
+
+    return S_OK;
+}
+
+static void WINAPI
+TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
+{
+    ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
+
+    TRACE("()\n");
+
+    EnterCriticalSection(&This->crit);
+
+    IRpcChannelBuffer_Release(This->chanbuf);
+    This->chanbuf = NULL;
+
+    LeaveCriticalSection(&This->crit);
+}
+
+
+static const IRpcProxyBufferVtbl tmproxyvtable = {
+    TMProxyImpl_QueryInterface,
+    TMProxyImpl_AddRef,
+    TMProxyImpl_Release,
+    TMProxyImpl_Connect,
+    TMProxyImpl_Disconnect
+};
+
+/* how much space do we use on stack in DWORD steps. */
+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:
+       return (sizeof(VARIANT)+3)/sizeof(DWORD);
+    default:
+       return 1;
+    }
+}
+
+static int
+_xsize(TYPEDESC *td) {
+    switch (td->vt) {
+    case VT_DATE:
+       return sizeof(DATE);
+    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_UI8:
+    case VT_I8:
+       return 8;
+    case VT_UI2:
+    case VT_I2:
+       return 2;
+    case VT_UI1:
+    case VT_I1:
+       return 1;
+    default:
+       return 4;
+    }
+}
+
+static HRESULT
+serialize_param(
+    ITypeInfo          *tinfo,
+    BOOL               writeit,
+    BOOL               debugout,
+    BOOL               dealloc,
+    TYPEDESC           *tdesc,
+    DWORD              *arg,
+    marshal_state      *buf)
+{
+    HRESULT hres = S_OK;
+
+    TRACE("(tdesc.vt %d)\n",tdesc->vt);
+
+    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_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) 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) 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,(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)
+                   TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
+           else
+                   TRACE_(olerelay)("<bstr NULL>");
+       }
+       if (writeit) {
+            BSTR bstr = (BSTR)*arg;
+            DWORD len;
+           if (!bstr) {
+               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)
+           SysFreeString((BSTR)*arg);
+       return S_OK;
+    }
+    case VT_PTR: {
+       DWORD cookie;
+       BOOL        derefhere = TRUE;
+
+       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) TRACE_(olerelay)("NULL");
+           return S_OK;
+       }
+       hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
+       if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
+       return hres;
+    }
+    case VT_UNKNOWN:
+       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) TRACE_(olerelay)("idisp(0x%lx)",*arg);
+       if (writeit)
+           hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
+       return hres;
+    case VT_VOID:
+       if (debugout) TRACE_(olerelay)("<void>");
+       return S_OK;
+    case VT_USERDEFINED: {
+       ITypeInfo       *tinfo2;
+       TYPEATTR        *tattr;
+
+       hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
+       if (hres) {
+           ERR("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_DISPATCH:
+       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) TRACE_(olerelay)("{");
+           for (i=0;i<tattr->cVars;i++) {
+               VARDESC *vdesc;
+               ELEMDESC *elem2;
+               TYPEDESC *tdesc2;
+
+               hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
+               if (hres) {
+                   ERR("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)
+                   TRACE_(olerelay)("%s=",relaystr(names[0]));
+               */
+               elem2 = &vdesc->elemdescVar;
+               tdesc2 = &elem2->tdesc;
+               hres = serialize_param(
+                   tinfo2,
+                   writeit,
+                   debugout,
+                   dealloc,
+                   tdesc2,
+                   (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
+                   buf
+               );
+                ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
+               if (hres!=S_OK)
+                   return hres;
+               if (debugout && (i<(tattr->cVars-1)))
+                   TRACE_(olerelay)(",");
+           }
+           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;
+           break;
+       }
+       ITypeInfo_Release(tinfo2);
+       return hres;
+    }
+    case VT_CARRAY: {
+       ARRAYDESC *adesc = tdesc->u.lpadesc;
+       int i, arrsize = 1;
+
+       if (debugout) TRACE_(olerelay)("carr");
+       for (i=0;i<adesc->cDims;i++) {
+           if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);
+           arrsize *= adesc->rgbounds[i].cElements;
+       }
+       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)) TRACE_(olerelay)(",");
+       }
+       if (debugout) TRACE_(olerelay)("]");
+       return S_OK;
+    }
+    default:
+       ERR("Unhandled marshal type %d.\n",tdesc->vt);
+       return S_OK;
+    }
+}
+
+static HRESULT
+deserialize_param(
+    ITypeInfo          *tinfo,
+    BOOL               readit,
+    BOOL               debugout,
+    BOOL               alloc,
+    TYPEDESC           *tdesc,
+    DWORD              *arg,
+    marshal_state      *buf)
+{
+    HRESULT hres = S_OK;
+
+    TRACE("vt %d at %p\n",tdesc->vt,arg);
+
+    while (1) {
+       switch (tdesc->vt) {
+       case VT_EMPTY:
+           if (debugout) TRACE_(olerelay)("<empty>");
+           return S_OK;
+       case VT_NULL:
+           if (debugout) TRACE_(olerelay)("<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) 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_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) {
+               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) 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;
+
+           if (readit) {
+               hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
+               if (hres) {
+                   ERR("failed to read bstr klen\n");
+                   return hres;
+               }
+               if (len == -1) {
+                   *arg = 0;
+                   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;
+                   }
+                   *arg = (DWORD)SysAllocStringLen(str,len);
+                   if (debugout) TRACE_(olerelay)("%s",relaystr(str));
+                   HeapFree(GetProcessHeap(),0,str);
+               }
+           } else {
+               *arg = 0;
+           }
+           return S_OK;
+       }
+       case VT_PTR: {
+           DWORD       cookie;
+           BOOL        derefhere = TRUE;
+
+           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);
+           }
+           /* 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));
+           }
+           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)
+               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)
+               TRACE_(olerelay)("idisp(%p)",arg);
+           return hres;
+       case VT_VOID:
+           if (debugout) TRACE_(olerelay)("<void>");
+           return S_OK;
+       case VT_USERDEFINED: {
+           ITypeInfo   *tinfo2;
+           TYPEATTR    *tattr;
+
+           hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
+           if (hres) {
+               ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
+               return hres;
+           }
+           hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
+           if (hres) {
+               ERR("Could not get typeattr in VT_USERDEFINED.\n");
+           } else {
+               switch (tattr->typekind) {
+               case TKIND_DISPATCH:
+               case TKIND_INTERFACE:
+                   if (readit)
+                       hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
+                   break;
+               case TKIND_RECORD: {
+                   int i;
+
+                   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) {
+                           ERR("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
+                       );
+                        ITypeInfo2_ReleaseVarDesc(tinfo2, vdesc);
+                       if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
+                   }
+                   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;
+                   break;
+               }
+           }
+           if (hres)
+               ERR("failed to stuballoc in TKIND_RECORD.\n");
+           ITypeInfo_Release(tinfo2);
+           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;
+       }
+       default:
+           ERR("No handler for VT type %d!\n",tdesc->vt);
+           return S_OK;
+       }
+    }
+}
+
+/* Searches function, also in inherited interfaces */
+static HRESULT
+_get_funcdesc(
+    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 = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i, fdesc);
+
+       if (hres) {
+           ITypeInfo   *tinfo2;
+           HREFTYPE    href;
+           TYPEATTR    *attr;
+
+           hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
+           if (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) {
+                   ERR("Did not find a reftype for interface offset %d?\n",j);
+                   break;
+               }
+               hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
+               if (hres) {
+                   ERR("Did not find a typeinfo for reftype %ld?\n",href);
+                   continue;
+               }
+               hres = _get_funcdesc(tinfo2,iMethod,tactual,fdesc,iname,fname);
+               ITypeInfo_Release(tinfo2);
+               if (!hres) return S_OK;
+           }
+           return hres;
+       }
+       if (((*fdesc)->oVft/4) == iMethod) {
+           if (fname)
+               ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
+           if (iname)
+               ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
+           return S_OK;
+       }
+       i++;
+    }
+}
+
+static DWORD
+xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
+{
+    DWORD              *args = ((DWORD*)&tpinfo)+1, *xargs;
+    const FUNCDESC     *fdesc;
+    HRESULT            hres;
+    int                        i, relaydeb = TRACE_ON(olerelay);
+    marshal_state      buf;
+    RPCOLEMESSAGE      msg;
+    ULONG              status;
+    BSTR               fname,iname;
+    BSTR               names[10];
+    UINT               nrofnames;
+    DWORD              remoteresult = 0;
+    ITypeInfo          *tinfo;
+    IRpcChannelBuffer *chanbuf;
+
+    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);
+        ITypeInfo_Release(tinfo);
+        LeaveCriticalSection(&tpinfo->crit);
+        return E_FAIL;
+    }
+
+    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)("->");
+       if (iname)
+           TRACE_(olerelay)("%s:",relaystr(iname));
+       if (fname)
+           TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
+       else
+           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(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
+       nrofnames = 0;
+    if (nrofnames > sizeof(names)/sizeof(names[0]))
+       ERR("Need more names!\n");
+
+    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) TRACE_(olerelay)(")");
+
+    memset(&msg,0,sizeof(msg));
+    msg.cbBuffer = buf.curoff;
+    msg.iMethod  = method;
+    hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
+    if (hres) {
+       ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
+       goto exit;
+    }
+    memcpy(msg.Buffer,buf.base,buf.curoff);
+    if (relaydeb) TRACE_(olerelay)("\n");
+    hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
+    if (hres) {
+       ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);
+       goto exit;
+    }
+
+    if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status);
+    if (buf.base)
+       buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
+    else
+       buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
+    buf.size = msg.cbBuffer;
+    memcpy(buf.base,msg.Buffer,buf.size);
+    buf.curoff = 0;
+
+    /* 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);
+    }
+
+    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);
+    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)
+{
+    HRESULT    hres;
+    ITypeInfo  *tinfo;
+    int                i, nroffuncs;
+    const FUNCDESC *fdesc;
+    TMProxyImpl        *proxy;
+    TYPEATTR   *typeattr;
+
+    TRACE("(...%s...)\n",debugstr_guid(riid));
+    hres = _get_typeinfo_for_iid(riid,&tinfo);
+    if (hres) {
+       ERR("No typeinfo for %s?\n",debugstr_guid(riid));
+       return hres;
+    }
+    nroffuncs = _nroffuncs(tinfo);
+    proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
+    if (!proxy) return E_OUTOFMEMORY;
+
+    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++) {
+       TMAsmProxy      *xasm = proxy->asmstubs+i;
+
+       switch (i) {
+       case 0:
+               proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
+               break;
+       case 1:
+               proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
+               break;
+       case 2:
+               proxy->lpvtbl[i] = ProxyIUnknown_Release;
+               break;
+       default: {
+               int j;
+               /* nrofargs without This */
+               int nrofargs;
+                ITypeInfo *tinfo2;
+               hres = _get_funcdesc(tinfo,i,&tinfo2,&fdesc,NULL,NULL);
+                ITypeInfo_Release(tinfo2);
+               if (hres) {
+                   ERR("GetFuncDesc %lx should not fail here.\n",hres);
+                   return hres;
+               }
+               /* some args take more than 4 byte on the stack */
+               nrofargs = 0;
+               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;
+               }
+/* popl %eax   -       return ptr
+ * pushl <nr>
+ * pushl %eax
+ * call xCall
+ * lret <nr> (+4)
+ *
+ *
+ * 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] = 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;
+    /* 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 {
+    const IRpcStubBufferVtbl   *lpvtbl;
+    LONG                       ref;
+
+    LPUNKNOWN                  pUnk;
+    ITypeInfo                  *tinfo;
+    IID                                iid;
+} TMStubImpl;
+
+static HRESULT WINAPI
+TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
+{
+    if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
+       *ppv = (LPVOID)iface;
+       IRpcStubBuffer_AddRef(iface);
+       return S_OK;
+    }
+    FIXME("%s, not supported IID.\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI
+TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
+    ULONG refCount = InterlockedIncrement(&This->ref);
+        
+    TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
+
+    return refCount;
+}
+
+static ULONG WINAPI
+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)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
+
+    TRACE("(%p)->(%p)\n", This, pUnkServer);
+
+    IUnknown_AddRef(pUnkServer);
+    This->pUnk = pUnkServer;
+    return S_OK;
+}
+
+static void WINAPI
+TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
+{
+    TMStubImpl *This = (TMStubImpl *)iface;
+
+    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)
+{
+    int                i;
+    const FUNCDESC *fdesc;
+    TMStubImpl *This = (TMStubImpl *)iface;
+    HRESULT    hres;
+    DWORD      *args, res, *xargs, nrofargs;
+    marshal_state      buf;
+    UINT       nrofnames;
+    BSTR       names[10];
+    BSTR       iname = NULL;
+    ITypeInfo  *tinfo;
+
+    memset(&buf,0,sizeof(buf));
+    buf.size   = xmsg->cbBuffer;
+    buf.base   = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
+    memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
+    buf.curoff = 0;
+
+    TRACE("...\n");
+
+    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,&tinfo,&fdesc,&iname,NULL);
+    if (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(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
+    if (nrofnames > sizeof(names)/sizeof(names[0])) {
+       ERR("Need more names!\n");
+    }
+
+    /*dump_FUNCDESC(fdesc);*/
+    nrofargs = 0;
+    for (i=0;i<fdesc->cParams;i++)
+       nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
+    args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
+    if (!args) return E_OUTOFMEMORY;
+
+    /* Allocate all stuff used by call. */
+    xargs = args+1;
+    for (i=0;i<fdesc->cParams;i++) {
+       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
+
+       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) {
+           ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
+           break;
+       }
+    }
+
+    args[0] = (DWORD)This->pUnk;
+    res = _invoke(
+       (*((FARPROC**)args[0]))[fdesc->oVft/4],
+       fdesc->callconv,
+       (xargs-args),
+       args
+    );
+    buf.curoff = 0;
+
+    xargs = args+1;
+    for (i=0;i<fdesc->cParams;i++) {
+       ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
+       hres = serialize_param(
+          tinfo,
+          elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
+          FALSE,
+          TRUE,
+          &elem->tdesc,
+          xargs,
+          &buf
+       );
+       xargs += _argsize(elem->tdesc.vt);
+       if (hres) {
+           ERR("Failed to stuballoc param, hres %lx\n",hres);
+           break;
+       }
+    }
+
+    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;
+    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
+TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
+    FIXME("Huh (%s)?\n",debugstr_guid(riid));
+    return NULL;
+}
+
+static ULONG WINAPI
+TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
+    TMStubImpl *This = (TMStubImpl *)iface;
+
+    FIXME("()\n");
+    return This->ref; /*FIXME? */
+}
+
+static HRESULT WINAPI
+TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
+    return E_NOTIMPL;
+}
+
+static void WINAPI
+TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
+    return;
+}
+
+static const IRpcStubBufferVtbl tmstubvtbl = {
+    TMStubImpl_QueryInterface,
+    TMStubImpl_AddRef,
+    TMStubImpl_Release,
+    TMStubImpl_Connect,
+    TMStubImpl_Disconnect,
+    TMStubImpl_Invoke,
+    TMStubImpl_IsIIDSupported,
+    TMStubImpl_CountRefs,
+    TMStubImpl_DebugServerQueryInterface,
+    TMStubImpl_DebugServerRelease
+};
+
+static HRESULT WINAPI
+PSFacBuf_CreateStub(
+    LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
+    IRpcStubBuffer** ppStub
+) {
+    HRESULT hres;
+    ITypeInfo  *tinfo;
+    TMStubImpl *stub;
+
+    TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
+    hres = _get_typeinfo_for_iid(riid,&tinfo);
+    if (hres) {
+       ERR("No typeinfo for %s?\n",debugstr_guid(riid));
+       return hres;
+    }
+    stub = CoTaskMemAlloc(sizeof(TMStubImpl));
+    if (!stub)
+       return E_OUTOFMEMORY;
+    stub->lpvtbl       = &tmstubvtbl;
+    stub->ref          = 1;
+    stub->tinfo                = tinfo;
+    memcpy(&(stub->iid),riid,sizeof(*riid));
+    hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
+    *ppStub            = (LPRPCSTUBBUFFER)stub;
+    TRACE("IRpcStubBuffer: %p\n", stub);
+    if (hres)
+       ERR("Connect to pUnkServer failed?\n");
+    return hres;
+}
+
+static const IPSFactoryBufferVtbl psfacbufvtbl = {
+    PSFacBuf_QueryInterface,
+    PSFacBuf_AddRef,
+    PSFacBuf_Release,
+    PSFacBuf_CreateProxy,
+    PSFacBuf_CreateStub
+};
+
+/* This is the whole PSFactoryBuffer object, just the vtableptr */
+static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
+
+/***********************************************************************
+ *           TMARSHAL_DllGetClassObject
+ */
+HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
+{
+    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
+       *ppv = &lppsfac;
+       return S_OK;
+    }
+    return E_NOINTERFACE;
+}