tmarshal.c 63.5 KB
Newer Older
1 2 3
/*
 *	TYPELIB Marshaler
 *
4
 *	Copyright 2002,2005	Marcus Meissner
5
 *
6 7 8
 * The olerelay debug channel allows you to see calls marshalled by
 * the typelib marshaller. It is not a generic COM relaying system.
 *
9 10 11 12 13 14 15 16 17 18 19 20
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23 24
 */

#include "config.h"
25
#include "wine/port.h"
26 27 28 29

#include <assert.h>
#include <stdlib.h>
#include <string.h>
30
#include <stdarg.h>
31 32 33
#include <stdio.h>
#include <ctype.h>

34
#define COBJMACROS
35 36
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
37

38
#include "winerror.h"
39
#include "windef.h"
40
#include "winbase.h"
41 42 43 44 45
#include "winnls.h"
#include "winreg.h"
#include "winuser.h"

#include "ole2.h"
46
#include "propidl.h" /* for LPSAFEARRAY_User* functions */
47
#include "typelib.h"
48
#include "variant.h"
49
#include "wine/debug.h"
50
#include "wine/exception.h"
51

52
static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
53

54 55
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(olerelay);
56

57 58 59 60
static HRESULT TMarshalDispatchChannel_Create(
    IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
    IRpcChannelBuffer **ppChannel);

61 62 63 64 65 66
typedef struct _marshal_state {
    LPBYTE	base;
    int		size;
    int		curoff;
} marshal_state;

67 68 69 70 71 72 73 74
/* 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;
}

75
static HRESULT
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
xbuf_resize(marshal_state *buf, DWORD newsize)
{
    if(buf->size >= newsize)
        return S_FALSE;

    if(buf->base)
    {
        buf->base = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf->base, newsize);
        if(!buf->base)
            return E_OUTOFMEMORY;
    }
    else
    {
        buf->base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
        if(!buf->base)
            return E_OUTOFMEMORY;
    }
93
    buf->size = newsize;
94 95 96 97
    return S_OK;
}

static HRESULT
98
xbuf_add(marshal_state *buf, const BYTE *stuff, DWORD size)
99 100 101 102 103 104 105
{
    HRESULT hr;

    if(buf->size - buf->curoff < size)
    {
        hr = xbuf_resize(buf, buf->size + size + 100);
        if(FAILED(hr)) return hr;
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    }
    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));
137
    
138 139
    *pUnk = NULL;
    hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
140 141 142 143 144
    if (hres) {
        ERR("xbuf_get failed\n");
        return hres;
    }
    
145
    if (xsize == 0) return S_OK;
146
    
147 148
    hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
    if (hres) {
149
	ERR("Stream create failed %x\n",hres);
150 151
	return hres;
    }
152
    
153
    hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
154
    if (hres) {
155
        ERR("stream write %x\n",hres);
156
        IStream_Release(pStm);
157 158 159
        return hres;
    }
    
160 161
    memset(&seekto,0,sizeof(seekto));
    hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
162
    if (hres) {
163
        ERR("Failed Seek %x\n",hres);
164
        IStream_Release(pStm);
165 166 167
        return hres;
    }
    
168 169
    hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
    if (hres) {
170
	ERR("Unmarshalling interface %s failed with %x\n",debugstr_guid(riid),hres);
171
	IStream_Release(pStm);
172 173
	return hres;
    }
174
    
175 176 177 178 179 180
    IStream_Release(pStm);
    return xbuf_skip(buf,xsize);
}

static HRESULT
_marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
181 182
    LPBYTE		tempbuf = NULL;
    IStream		*pStm = NULL;
183 184 185 186 187 188 189
    STATSTG		ststg;
    ULARGE_INTEGER	newpos;
    LARGE_INTEGER	seekto;
    ULONG		res;
    DWORD		xsize;
    HRESULT		hres;

190
    if (!pUnk) {
191 192 193 194 195
	/* 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.
	 */
196
        WARN("pUnk is NULL\n");
197 198
        xsize = 0;
        return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
199
    }
200

201 202
    hres = E_FAIL;

203
    TRACE("...%s...\n",debugstr_guid(riid));
204
    
205 206
    hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
    if (hres) {
207
	ERR("Stream create failed %x\n",hres);
208 209
	goto fail;
    }
210
    
211
    hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
212
    if (hres) {
213
	ERR("Marshalling interface %s failed with %x\n", debugstr_guid(riid), hres);
214 215
	goto fail;
    }
216
    
217
    hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
218 219 220 221 222
    if (hres) {
        ERR("Stream stat failed\n");
        goto fail;
    }
    
223
    tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
224 225
    memset(&seekto,0,sizeof(seekto));
    hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
226
    if (hres) {
227
        ERR("Failed Seek %x\n",hres);
228 229 230
        goto fail;
    }
    
231
    hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
232
    if (hres) {
233
        ERR("Failed Read %x\n",hres);
234 235 236
        goto fail;
    }
    
237
    xsize = ststg.cbSize.u.LowPart;
238
    xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
239
    hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
240
    
241
    HeapFree(GetProcessHeap(),0,tempbuf);
242 243
    IStream_Release(pStm);
    
244
    return hres;
245
    
246 247 248
fail:
    xsize = 0;
    xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
249 250
    if (pStm) IUnknown_Release(pStm);
    HeapFree(GetProcessHeap(), 0, tempbuf);
251 252 253 254 255 256 257
    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)) {
258
        *ppv = iface;
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	/* 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];
276 277
    DWORD	tlguidlen, verlen, type;
    LONG	tlfnlen;
278 279
    ITypeLib	*tl;

280
    sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
281 282 283 284 285 286
	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)) {
287
	ERR("No %s key found.\n",interfacekey);
288 289 290
       	return E_FAIL;
    }
    tlguidlen = sizeof(tlguid);
291
    if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
292
	ERR("Getting typelib guid failed.\n");
293 294 295 296
	RegCloseKey(ikey);
	return E_FAIL;
    }
    verlen = sizeof(ver);
297
    if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
298
	ERR("Could not get version value?\n");
299 300 301 302
	RegCloseKey(ikey);
	return E_FAIL;
    }
    RegCloseKey(ikey);
303
    sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win%u",tlguid,ver,(sizeof(void*) == 8) ? 64 : 32);
304 305
    tlfnlen = sizeof(tlfn);
    if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
306
	ERR("Could not get typelib fn?\n");
307 308
	return E_FAIL;
    }
309
    MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, sizeof(tlfnW) / sizeof(tlfnW[0]));
310 311 312 313 314 315 316 317 318 319 320
    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;
    }
321
    ITypeLib_Release(tl);
322 323 324
    return hres;
}

325
/*
326 327
 * Determine the number of functions including all inherited functions
 * and well as the size of the vtbl.
328
 * Note for non-dual dispinterfaces we simply return the size of IDispatch.
329
 */
330 331
static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num,
                            unsigned int *vtbl_size)
332
{
333
    HRESULT hr;
334 335
    TYPEATTR *attr;
    ITypeInfo *tinfo2;
336
    UINT inherited_funcs = 0, i;
337

338
    *num = 0;
339 340 341 342 343 344 345
    if(vtbl_size) *vtbl_size = 0;

    hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
    if (hr)
    {
        ERR("GetTypeAttr failed with %x\n", hr);
        return hr;
346
    }
347

348
    if(attr->typekind == TKIND_DISPATCH)
349
    {
350
        if(attr->wTypeFlags & TYPEFLAG_FDUAL)
351
        {
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
            HREFTYPE href;

            ITypeInfo_ReleaseTypeAttr(tinfo, attr);
            hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
            if(FAILED(hr))
            {
                ERR("Unable to get interface href from dual dispinterface\n");
                return hr;
            }
            hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
            if(FAILED(hr))
            {
                ERR("Unable to get interface from dual dispinterface\n");
                return hr;
            }
            hr = num_of_funcs(tinfo2, num, vtbl_size);
            ITypeInfo_Release(tinfo2);
            return hr;
370
        }
371
        else /* non-dual dispinterface */
372
        {
373 374 375 376 377
            /* These will be the size of IDispatchVtbl */
            *num = attr->cbSizeVft / sizeof(void *);
            if(vtbl_size) *vtbl_size = attr->cbSizeVft;
            ITypeInfo_ReleaseTypeAttr(tinfo, attr);
            return hr;
378 379
        }
    }
380 381

    for (i = 0; i < attr->cImplTypes; i++)
382
    {
383 384 385 386 387 388 389 390 391 392 393 394 395 396
        HREFTYPE href;
        ITypeInfo *pSubTypeInfo;
        UINT sub_funcs;

        hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
        if (FAILED(hr)) goto end;
        hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
        if (FAILED(hr)) goto end;

        hr = num_of_funcs(pSubTypeInfo, &sub_funcs, NULL);
        ITypeInfo_Release(pSubTypeInfo);

        if(FAILED(hr)) goto end;
        inherited_funcs += sub_funcs;
397
    }
398

399 400 401
    *num = inherited_funcs + attr->cFuncs;
    if(vtbl_size) *vtbl_size = attr->cbSizeVft;

402 403
 end:
    ITypeInfo_ReleaseTypeAttr(tinfo, attr);
404
    return hr;
405 406
}

407 408
#ifdef __i386__

409 410
#include "pshpack1.h"

411 412 413
typedef struct _TMAsmProxy {
    BYTE	popleax;
    BYTE	pushlval;
414
    DWORD	nr;
415 416 417 418 419
    BYTE	pushleax;
    BYTE	lcall;
    DWORD	xcall;
    BYTE	lret;
    WORD	bytestopop;
420
    BYTE	nop;
421 422 423
} TMAsmProxy;

#include "poppack.h"
424

425
#else /* __i386__ */
426 427 428
# warning You need to implement stubless proxies for your architecture
typedef struct _TMAsmProxy {
} TMAsmProxy;
429 430
#endif

431
typedef struct _TMProxyImpl {
432
    LPVOID                             *lpvtbl;
433
    IRpcProxyBuffer                     IRpcProxyBuffer_iface;
434
    LONG				ref;
435 436 437 438 439

    TMAsmProxy				*asmstubs;
    ITypeInfo*				tinfo;
    IRpcChannelBuffer*			chanbuf;
    IID					iid;
440
    CRITICAL_SECTION	crit;
441
    IUnknown				*outerunknown;
442
    IDispatch				*dispatch;
443
    IRpcProxyBuffer			*dispatch_proxy;
444 445
} TMProxyImpl;

446 447
static inline TMProxyImpl *impl_from_IRpcProxyBuffer( IRpcProxyBuffer *iface )
{
448
    return CONTAINING_RECORD(iface, TMProxyImpl, IRpcProxyBuffer_iface);
449 450
}

451
static HRESULT WINAPI
452 453
TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
{
454 455
    TRACE("()\n");
    if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
456
        *ppv = iface;
457 458
        IRpcProxyBuffer_AddRef(iface);
        return S_OK;
459 460 461 462 463 464
    }
    FIXME("no interface for %s\n",debugstr_guid(riid));
    return E_NOINTERFACE;
}

static ULONG WINAPI
465 466
TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
{
467
    TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
468
    ULONG refCount = InterlockedIncrement(&This->ref);
469

470
    TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
471

472
    return refCount;
473 474 475
}

static ULONG WINAPI
476 477
TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
{
478
    TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
479
    ULONG refCount = InterlockedDecrement(&This->ref);
480

481
    TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
482

483
    if (!refCount)
484
    {
485
        if (This->dispatch_proxy) IRpcProxyBuffer_Release(This->dispatch_proxy);
486
        This->crit.DebugInfo->Spare[0] = 0;
487 488 489
        DeleteCriticalSection(&This->crit);
        if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
        VirtualFree(This->asmstubs, 0, MEM_RELEASE);
490
        HeapFree(GetProcessHeap(), 0, This->lpvtbl);
491
        ITypeInfo_Release(This->tinfo);
492 493
        CoTaskMemFree(This);
    }
494
    return refCount;
495 496 497 498
}

static HRESULT WINAPI
TMProxyImpl_Connect(
499 500
    LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
{
501
    TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
502 503 504 505

    TRACE("(%p)\n", pRpcChannelBuffer);

    EnterCriticalSection(&This->crit);
506

507
    IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
508
    This->chanbuf = pRpcChannelBuffer;
509 510 511

    LeaveCriticalSection(&This->crit);

512
    if (This->dispatch_proxy)
513 514 515 516 517
    {
        IRpcChannelBuffer *pDelegateChannel;
        HRESULT hr = TMarshalDispatchChannel_Create(pRpcChannelBuffer, &This->iid, &pDelegateChannel);
        if (FAILED(hr))
            return hr;
518 519 520
        hr = IRpcProxyBuffer_Connect(This->dispatch_proxy, pDelegateChannel);
        IRpcChannelBuffer_Release(pDelegateChannel);
        return hr;
521
    }
522

523 524 525 526
    return S_OK;
}

static void WINAPI
527 528
TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
{
529
    TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
530 531 532 533

    TRACE("()\n");

    EnterCriticalSection(&This->crit);
534 535 536

    IRpcChannelBuffer_Release(This->chanbuf);
    This->chanbuf = NULL;
537 538

    LeaveCriticalSection(&This->crit);
539 540 541

    if (This->dispatch_proxy)
        IRpcProxyBuffer_Disconnect(This->dispatch_proxy);
542 543 544
}


545
static const IRpcProxyBufferVtbl tmproxyvtable = {
546 547 548 549 550 551 552
    TMProxyImpl_QueryInterface,
    TMProxyImpl_AddRef,
    TMProxyImpl_Release,
    TMProxyImpl_Connect,
    TMProxyImpl_Disconnect
};

553
/* how much space do we use on stack in DWORD steps. */
554 555 556
static int
_argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
    switch (tdesc->vt) {
557
    case VT_I8:
558 559
    case VT_UI8:
	return 8/sizeof(DWORD);
560 561 562 563
    case VT_R8:
        return sizeof(double)/sizeof(DWORD);
    case VT_CY:
        return sizeof(CY)/sizeof(DWORD);
564 565
    case VT_DATE:
	return sizeof(DATE)/sizeof(DWORD);
566 567
    case VT_DECIMAL:
        return (sizeof(DECIMAL)+3)/sizeof(DWORD);
568 569
    case VT_VARIANT:
	return (sizeof(VARIANT)+3)/sizeof(DWORD);
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
    case VT_USERDEFINED:
    {
        ITypeInfo *tinfo2;
        TYPEATTR *tattr;
        HRESULT hres;
        DWORD ret;

        hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
        if (FAILED(hres))
            return 0; /* should fail critically in serialize_param */
        ITypeInfo_GetTypeAttr(tinfo2,&tattr);
        ret = (tattr->cbSizeInstance+3)/sizeof(DWORD);
        ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
        ITypeInfo_Release(tinfo2);
        return ret;
    }
586 587 588 589 590
    default:
	return 1;
    }
}

591
/* how much space do we use on the heap (in bytes) */
592
static int
593
_xsize(const TYPEDESC *td, ITypeInfo *tinfo) {
594
    switch (td->vt) {
595 596
    case VT_DATE:
	return sizeof(DATE);
597 598
    case VT_CY:
        return sizeof(CY);
599
    case VT_VARIANT:
600
	return sizeof(VARIANT);
601 602
    case VT_CARRAY: {
	int i, arrsize = 1;
603
	const ARRAYDESC *adesc = td->u.lpadesc;
604 605 606

	for (i=0;i<adesc->cDims;i++)
	    arrsize *= adesc->rgbounds[i].cElements;
607
	return arrsize*_xsize(&adesc->tdescElem, tinfo);
608
    }
609 610
    case VT_UI8:
    case VT_I8:
611
    case VT_R8:
612
	return 8;
613 614
    case VT_UI2:
    case VT_I2:
615
    case VT_BOOL:
616 617 618 619
	return 2;
    case VT_UI1:
    case VT_I1:
	return 1;
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
    case VT_USERDEFINED:
    {
        ITypeInfo *tinfo2;
        TYPEATTR *tattr;
        HRESULT hres;
        DWORD ret;

        hres = ITypeInfo_GetRefTypeInfo(tinfo,td->u.hreftype,&tinfo2);
        if (FAILED(hres))
            return 0;
        ITypeInfo_GetTypeAttr(tinfo2,&tattr);
        ret = tattr->cbSizeInstance;
        ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
        ITypeInfo_Release(tinfo2);
        return ret;
    }
636 637 638 639 640
    default:
	return 4;
    }
}

641 642 643 644 645 646 647 648 649 650 651
/* Whether we pass this type by reference or by value */
static int
_passbyref(const TYPEDESC *td, ITypeInfo *tinfo) {
    if (td->vt == VT_USERDEFINED ||
        td->vt == VT_VARIANT     ||
        td->vt == VT_PTR)
        return 1;

    return 0;
}

652
static HRESULT
653 654 655 656 657 658 659
serialize_param(
    ITypeInfo		*tinfo,
    BOOL		writeit,
    BOOL		debugout,
    BOOL		dealloc,
    TYPEDESC		*tdesc,
    DWORD		*arg,
660 661
    marshal_state	*buf)
{
662
    HRESULT hres = S_OK;
663
    VARTYPE vartype;
664

665
    TRACE("(tdesc.vt %s)\n",debugstr_vt(tdesc->vt));
666

667 668 669 670 671
    vartype = tdesc->vt;
    if ((vartype & 0xf000) == VT_ARRAY)
        vartype = VT_SAFEARRAY;

    switch (vartype) {
672
    case VT_DATE:
673 674
    case VT_I8:
    case VT_UI8:
675
    case VT_R8:
676
    case VT_CY:
677
	hres = S_OK;
678
	if (debugout) TRACE_(olerelay)("%x%x\n",arg[0],arg[1]);
679 680 681
	if (writeit)
	    hres = xbuf_add(buf,(LPBYTE)arg,8);
	return hres;
682
    case VT_ERROR:
683
    case VT_INT:
684
    case VT_UINT:
685
    case VT_I4:
686
    case VT_R4:
687
    case VT_UI4:
688
	hres = S_OK;
689
	if (debugout) TRACE_(olerelay)("%x\n",*arg);
690 691 692 693
	if (writeit)
	    hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
	return hres;
    case VT_I2:
694
    case VT_UI2:
695
    case VT_BOOL:
696
	hres = S_OK;
697
	if (debugout) TRACE_(olerelay)("%04x\n",*arg & 0xffff);
698 699 700 701
	if (writeit)
	    hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
	return hres;
    case VT_I1:
702 703
    case VT_UI1:
	hres = S_OK;
704
	if (debugout) TRACE_(olerelay)("%02x\n",*arg & 0xff);
705 706 707
	if (writeit)
	    hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
	return hres;
708
    case VT_VARIANT: {
709 710 711 712 713 714 715 716
        if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(V_VT((VARIANT *)arg)),debugstr_vf(V_VT((VARIANT *)arg)));
        if (writeit)
        {
            ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
            ULONG size = VARIANT_UserSize(&flags, buf->curoff, (VARIANT *)arg);
            xbuf_resize(buf, size);
            VARIANT_UserMarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
            buf->curoff = size;
717
        }
718 719 720 721
        if (dealloc)
        {
            ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
            VARIANT_UserFree(&flags, (VARIANT *)arg);
722 723 724
        }
        return S_OK;
    }
725
    case VT_BSTR: {
726
	if (writeit && debugout) {
727 728
	    if (*arg)
                   TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
729
	    else
730
		    TRACE_(olerelay)("<bstr NULL>");
731
	}
732 733 734 735 736 737 738 739 740 741 742 743 744 745
        if (writeit)
        {
            ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
            ULONG size = BSTR_UserSize(&flags, buf->curoff, (BSTR *)arg);
            xbuf_resize(buf, size);
            BSTR_UserMarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
            buf->curoff = size;
        }
        if (dealloc)
        {
            ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
            BSTR_UserFree(&flags, (BSTR *)arg);
        }
        return S_OK;
746 747 748
    }
    case VT_PTR: {
	DWORD cookie;
749
	BOOL        derefhere = TRUE;
750

751 752 753 754 755 756
	if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
	    ITypeInfo	*tinfo2;
	    TYPEATTR	*tattr;

	    hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
	    if (hres) {
757
		ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
758 759 760 761
		return hres;
	    }
	    ITypeInfo_GetTypeAttr(tinfo2,&tattr);
	    switch (tattr->typekind) {
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
            case TKIND_ALIAS:
                if (tattr->tdescAlias.vt == VT_USERDEFINED)
                {
                    DWORD href = tattr->tdescAlias.u.hreftype;
                    ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
                    ITypeInfo_Release(tinfo2);
                    hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
                    if (hres) {
                        ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
                        return hres;
                    }
                    ITypeInfo_GetTypeAttr(tinfo2,&tattr);
                    derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
                }
                break;
777 778 779 780 781 782 783 784 785 786 787 788
	    case TKIND_ENUM:	/* confirmed */
	    case TKIND_RECORD:	/* FIXME: mostly untested */
		break;
	    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;
	    }
789
	    ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
790 791
	    ITypeInfo_Release(tinfo2);
	}
792

793
	if (debugout) TRACE_(olerelay)("*");
794 795 796 797 798 799
	/* 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;
800
	if (!*arg) {
801
	    if (debugout) TRACE_(olerelay)("NULL");
802 803 804
	    return S_OK;
	}
	hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
805
	if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
806
	return hres;
807 808
    }
    case VT_UNKNOWN:
809
	if (debugout) TRACE_(olerelay)("unk(0x%x)",*arg);
810 811
	if (writeit)
	    hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
812
	if (dealloc && *(IUnknown **)arg)
813
	    IUnknown_Release((LPUNKNOWN)*arg);
814 815
	return hres;
    case VT_DISPATCH:
816
	if (debugout) TRACE_(olerelay)("idisp(0x%x)",*arg);
817 818
	if (writeit)
	    hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
819
	if (dealloc && *(IUnknown **)arg)
820
	    IUnknown_Release((LPUNKNOWN)*arg);
821 822
	return hres;
    case VT_VOID:
823
	if (debugout) TRACE_(olerelay)("<void>");
824
	return S_OK;
825 826 827 828 829 830
    case VT_USERDEFINED: {
	ITypeInfo	*tinfo2;
	TYPEATTR	*tattr;

	hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
	if (hres) {
831
	    ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
832 833 834 835
	    return hres;
	}
	ITypeInfo_GetTypeAttr(tinfo2,&tattr);
	switch (tattr->typekind) {
836
	case TKIND_DISPATCH:
837
	case TKIND_INTERFACE:
838 839
	    if (writeit)
	       hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
840 841
	    if (dealloc)
	        IUnknown_Release((LPUNKNOWN)arg);
842
	    break;
843 844
	case TKIND_RECORD: {
	    int i;
845
	    if (debugout) TRACE_(olerelay)("{");
846 847 848 849 850 851 852
	    for (i=0;i<tattr->cVars;i++) {
		VARDESC *vdesc;
		ELEMDESC *elem2;
		TYPEDESC *tdesc2;

		hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
		if (hres) {
853
		    ERR("Could not get vardesc of %d\n",i);
854 855 856 857 858 859 860 861 862 863 864 865 866
		    return hres;
		}
		elem2 = &vdesc->elemdescVar;
		tdesc2 = &elem2->tdesc;
		hres = serialize_param(
		    tinfo2,
		    writeit,
		    debugout,
		    dealloc,
		    tdesc2,
		    (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
		    buf
		);
867
                ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
868 869 870
		if (hres!=S_OK)
		    return hres;
		if (debugout && (i<(tattr->cVars-1)))
871
		    TRACE_(olerelay)(",");
872
	    }
873
	    if (debugout) TRACE_(olerelay)("}");
874
	    break;
875
	}
876
	case TKIND_ALIAS:
877 878
	    hres = serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
	    break;
879 880
	case TKIND_ENUM:
	    hres = S_OK;
881
	    if (debugout) TRACE_(olerelay)("%x",*arg);
882 883
	    if (writeit)
	        hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
884
	    break;
885 886 887
	default:
	    FIXME("Unhandled typekind %d\n",tattr->typekind);
	    hres = E_FAIL;
888 889
	    break;
	}
890
	ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
891 892 893
	ITypeInfo_Release(tinfo2);
	return hres;
    }
894 895 896 897
    case VT_CARRAY: {
	ARRAYDESC *adesc = tdesc->u.lpadesc;
	int i, arrsize = 1;

898
	if (debugout) TRACE_(olerelay)("carr");
899
	for (i=0;i<adesc->cDims;i++) {
900
	    if (debugout) TRACE_(olerelay)("[%d]",adesc->rgbounds[i].cElements);
901 902
	    arrsize *= adesc->rgbounds[i].cElements;
	}
903
	if (debugout) TRACE_(olerelay)("(vt %s)",debugstr_vt(adesc->tdescElem.vt));
904
	if (debugout) TRACE_(olerelay)("[");
905
	for (i=0;i<arrsize;i++) {
906 907
            LPBYTE base = _passbyref(&adesc->tdescElem, tinfo) ? (LPBYTE) *arg : (LPBYTE) arg;
	    hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)base+i*_xsize(&adesc->tdescElem, tinfo)), buf);
908 909
	    if (hres)
		return hres;
910
	    if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
911
	}
912
	if (debugout) TRACE_(olerelay)("]");
913 914
	if (dealloc)
	    HeapFree(GetProcessHeap(), 0, *(void **)arg);
915 916
	return S_OK;
    }
917 918 919
    case VT_SAFEARRAY: {
        if (writeit)
        {
920 921
            ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
            ULONG size = LPSAFEARRAY_UserSize(&flags, buf->curoff, (LPSAFEARRAY *)arg);
922 923 924 925
            xbuf_resize(buf, size);
            LPSAFEARRAY_UserMarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
            buf->curoff = size;
        }
926 927 928 929 930
        if (dealloc)
        {
            ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
            LPSAFEARRAY_UserFree(&flags, (LPSAFEARRAY *)arg);
        }
931 932
        return S_OK;
    }
933
    default:
934 935 936 937 938 939 940 941 942 943 944 945 946
	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,
947 948
    marshal_state	*buf)
{
949
    HRESULT hres = S_OK;
950
    VARTYPE vartype;
951

952
    TRACE("vt %s at %p\n",debugstr_vt(tdesc->vt),arg);
953

954 955 956 957
    vartype = tdesc->vt;
    if ((vartype & 0xf000) == VT_ARRAY)
        vartype = VT_SAFEARRAY;

958
    while (1) {
959
	switch (vartype) {
960
	case VT_VARIANT: {
961 962 963 964 965 966
	    if (readit)
	    {
		ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
		unsigned char *buffer;
		buffer = VARIANT_UserUnmarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
		buf->curoff = buffer - buf->base;
967
	    }
968
	    return S_OK;
969
	}
970
        case VT_DATE:
971 972
        case VT_I8:
        case VT_UI8:
973
        case VT_R8:
974
        case VT_CY:
975 976 977 978
	    if (readit) {
		hres = xbuf_get(buf,(LPBYTE)arg,8);
		if (hres) ERR("Failed to read integer 8 byte\n");
	    }
979
	    if (debugout) TRACE_(olerelay)("%x%x",arg[0],arg[1]);
980
	    return hres;
981
        case VT_ERROR:
982
        case VT_I4:
983
        case VT_INT:
984 985 986
        case VT_UINT:
        case VT_R4:
        case VT_UI4:
987 988
	    if (readit) {
		hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
989
		if (hres) ERR("Failed to read integer 4 byte\n");
990
	    }
991
	    if (debugout) TRACE_(olerelay)("%x",*arg);
992
	    return hres;
993 994
        case VT_I2:
        case VT_UI2:
995
        case VT_BOOL:
996 997 998 999 1000 1001
	    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);
	    }
1002
	    if (debugout) TRACE_(olerelay)("%04x",*arg & 0xffff);
1003 1004 1005 1006 1007 1008 1009 1010 1011
	    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);
	    }
1012
	    if (debugout) TRACE_(olerelay)("%02x",*arg & 0xff);
1013
	    return hres;
1014
	case VT_BSTR: {
1015 1016 1017 1018 1019 1020
	    if (readit)
	    {
		ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
		unsigned char *buffer;
		buffer = BSTR_UserUnmarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
		buf->curoff = buffer - buf->base;
1021
		if (debugout) TRACE_(olerelay)("%s",debugstr_w(*(BSTR *)arg));
1022 1023
	    }
	    return S_OK;
1024
	}
1025 1026
	case VT_PTR: {
	    DWORD	cookie;
1027
	    BOOL        derefhere = TRUE;
1028

1029 1030 1031 1032 1033 1034
	    if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
		ITypeInfo	*tinfo2;
		TYPEATTR	*tattr;

		hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
		if (hres) {
1035
		    ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1036 1037 1038 1039
		    return hres;
		}
		ITypeInfo_GetTypeAttr(tinfo2,&tattr);
		switch (tattr->typekind) {
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
                case TKIND_ALIAS:
                    if (tattr->tdescAlias.vt == VT_USERDEFINED)
                    {
                        DWORD href = tattr->tdescAlias.u.hreftype;
                        ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
                        ITypeInfo_Release(tinfo2);
                        hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
                        if (hres) {
                            ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
                            return hres;
                        }
                        ITypeInfo_GetTypeAttr(tinfo2,&tattr);
                        derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
                    }
                    break;
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
		case TKIND_ENUM:	/* confirmed */
		case TKIND_RECORD:	/* FIXME: mostly untested */
		    break;
		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;
		}
1067
		ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1068 1069
		ITypeInfo_Release(tinfo2);
	    }
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
	    /* 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;
1083
	    }
1084
	    if (debugout) TRACE_(olerelay)("*");
1085
	    if (alloc) {
1086
		/* Allocate space for the referenced struct */
1087
		if (derefhere)
1088
		    *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo));
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
	    }
	    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)
1103
		TRACE_(olerelay)("unk(%p)",arg);
1104 1105 1106 1107 1108 1109
	    return hres;
	case VT_DISPATCH:
	    hres = S_OK;
	    if (readit)
		hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
	    if (debugout)
1110
		TRACE_(olerelay)("idisp(%p)",arg);
1111 1112
	    return hres;
	case VT_VOID:
1113
	    if (debugout) TRACE_(olerelay)("<void>");
1114 1115 1116 1117 1118 1119 1120
	    return S_OK;
	case VT_USERDEFINED: {
	    ITypeInfo	*tinfo2;
	    TYPEATTR	*tattr;

	    hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
	    if (hres) {
1121
		ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
1122 1123 1124 1125
		return hres;
	    }
	    hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
	    if (hres) {
1126
		ERR("Could not get typeattr in VT_USERDEFINED.\n");
1127 1128
	    } else {
		switch (tattr->typekind) {
1129
		case TKIND_DISPATCH:
1130 1131 1132 1133 1134 1135 1136
		case TKIND_INTERFACE:
		    if (readit)
			hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
		    break;
		case TKIND_RECORD: {
		    int i;

1137
		    if (debugout) TRACE_(olerelay)("{");
1138 1139 1140 1141 1142
		    for (i=0;i<tattr->cVars;i++) {
			VARDESC *vdesc;

			hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
			if (hres) {
1143
			    ERR("Could not get vardesc of %d\n",i);
1144 1145
			    ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
			    ITypeInfo_Release(tinfo2);
1146 1147 1148 1149 1150 1151 1152 1153
			    return hres;
			}
			hres = deserialize_param(
			    tinfo2,
			    readit,
			    debugout,
			    alloc,
			    &vdesc->elemdescVar.tdesc,
1154
			    (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
1155 1156
			    buf
			);
1157
                        ITypeInfo2_ReleaseVarDesc(tinfo2, vdesc);
1158
		        if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1159
		    }
1160
		    if (debugout) TRACE_(olerelay)("}");
1161 1162
		    break;
		}
1163
		case TKIND_ALIAS:
1164 1165
		    hres = deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
		    break;
1166 1167 1168 1169 1170
		case TKIND_ENUM:
		    if (readit) {
		        hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
		        if (hres) ERR("Failed to read enum (4 byte)\n");
		    }
1171
		    if (debugout) TRACE_(olerelay)("%x",*arg);
1172
		    break;
1173 1174 1175
		default:
		    ERR("Unhandled typekind %d\n",tattr->typekind);
		    hres = E_FAIL;
1176 1177
		    break;
		}
1178
		ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1179 1180
	    }
	    if (hres)
1181
		ERR("failed to stuballoc in TKIND_RECORD.\n");
1182
	    ITypeInfo_Release(tinfo2);
1183 1184
	    return hres;
	}
1185 1186
	case VT_CARRAY: {
	    /* arg is pointing to the start of the array. */
1187
            LPBYTE base = (LPBYTE) arg;
1188 1189 1190 1191 1192 1193
	    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;
1194 1195 1196 1197 1198
            if (_passbyref(&adesc->tdescElem, tinfo))
            {
	        base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo) * arrsize);
                *arg = (DWORD) base;
            }
1199 1200 1201 1202 1203 1204 1205
	    for (i=0;i<arrsize;i++)
		deserialize_param(
		    tinfo,
		    readit,
		    debugout,
		    alloc,
		    &adesc->tdescElem,
1206
		    (DWORD*)(base + i*_xsize(&adesc->tdescElem, tinfo)),
1207 1208 1209 1210
		    buf
		);
	    return S_OK;
	}
1211 1212 1213
    case VT_SAFEARRAY: {
	    if (readit)
	    {
1214
		ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1215 1216 1217 1218 1219 1220
		unsigned char *buffer;
		buffer = LPSAFEARRAY_UserUnmarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
		buf->curoff = buffer - buf->base;
	    }
	    return S_OK;
	}
1221
	default:
1222 1223
	    ERR("No handler for VT type %d!\n",tdesc->vt);
	    return S_OK;
1224
	}
1225 1226 1227
    }
}

1228 1229 1230
/* Retrieves a function's funcdesc, searching back into inherited interfaces. */
static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, const FUNCDESC **fdesc,
                            BSTR *iname, BSTR *fname, UINT *num)
1231
{
1232 1233 1234 1235
    HRESULT hr;
    UINT i, impl_types;
    UINT inherited_funcs = 0;
    TYPEATTR *attr;
1236 1237 1238

    if (fname) *fname = NULL;
    if (iname) *iname = NULL;
1239 1240
    if (num) *num = 0;
    *tactual = NULL;
1241

1242 1243 1244 1245 1246 1247
    hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
    if (FAILED(hr))
    {
        ERR("GetTypeAttr failed with %x\n",hr);
        return hr;
    }
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278

    if(attr->typekind == TKIND_DISPATCH)
    {
        if(attr->wTypeFlags & TYPEFLAG_FDUAL)
        {
            HREFTYPE href;
            ITypeInfo *tinfo2;

            hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
            if(FAILED(hr))
            {
                ERR("Cannot get interface href from dual dispinterface\n");
                ITypeInfo_ReleaseTypeAttr(tinfo, attr);
                return hr;
            }
            hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
            if(FAILED(hr))
            {
                ERR("Cannot get interface from dual dispinterface\n");
                ITypeInfo_ReleaseTypeAttr(tinfo, attr);
                return hr;
            }
            hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
            ITypeInfo_Release(tinfo2);
            ITypeInfo_ReleaseTypeAttr(tinfo, attr);
            return hr;
        }
        ERR("Shouldn't be called with a non-dual dispinterface\n");
        return E_FAIL;
    }

1279 1280
    impl_types = attr->cImplTypes;
    ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1281

1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
    for (i = 0; i < impl_types; i++)
    {
        HREFTYPE href;
        ITypeInfo *pSubTypeInfo;
        UINT sub_funcs;

        hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
        if (FAILED(hr)) return hr;
        hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
        if (FAILED(hr)) return hr;

        hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
        inherited_funcs += sub_funcs;
        ITypeInfo_Release(pSubTypeInfo);
        if(SUCCEEDED(hr)) return hr;
    }
    if(iMethod < inherited_funcs)
    {
        ERR("shouldn't be here\n");
        return E_INVALIDARG;
    }
1303

1304 1305 1306 1307 1308 1309 1310 1311
    for(i = inherited_funcs; i <= iMethod; i++)
    {
        hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
        if(FAILED(hr))
        {
            if(num) *num = i;
            return hr;
        }
1312
    }
1313 1314 1315 1316 1317 1318 1319 1320

    /* found it. We don't care about num so zero it */
    if(num) *num = 0;
    *tactual = tinfo;
    ITypeInfo_AddRef(*tactual);
    if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
    if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
    return S_OK;
1321 1322
}

1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
static inline BOOL is_in_elem(const ELEMDESC *elem)
{
    return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
}

static inline BOOL is_out_elem(const ELEMDESC *elem)
{
    return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
}

1333
static DWORD
1334 1335
xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
{
1336
    DWORD		*args = ((DWORD*)&tpinfo)+1, *xargs;
1337
    const FUNCDESC	*fdesc;
1338 1339 1340 1341 1342 1343 1344
    HRESULT		hres;
    int			i, relaydeb = TRACE_ON(olerelay);
    marshal_state	buf;
    RPCOLEMESSAGE	msg;
    ULONG		status;
    BSTR		fname,iname;
    BSTR		names[10];
Mike McCormack's avatar
Mike McCormack committed
1345
    UINT		nrofnames;
1346
    DWORD		remoteresult = 0;
1347
    ITypeInfo 		*tinfo;
1348
    IRpcChannelBuffer *chanbuf;
1349

1350 1351
    EnterCriticalSection(&tpinfo->crit);

1352
    hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1353
    if (hres) {
1354
        ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1355
        LeaveCriticalSection(&tpinfo->crit);
1356
        return E_FAIL;
1357 1358
    }

1359 1360 1361
    if (!tpinfo->chanbuf)
    {
        WARN("Tried to use disconnected proxy\n");
1362
        ITypeInfo_Release(tinfo);
1363 1364 1365
        LeaveCriticalSection(&tpinfo->crit);
        return RPC_E_DISCONNECTED;
    }
1366 1367 1368 1369
    chanbuf = tpinfo->chanbuf;
    IRpcChannelBuffer_AddRef(chanbuf);

    LeaveCriticalSection(&tpinfo->crit);
1370

1371
    if (relaydeb) {
1372
       TRACE_(olerelay)("->");
1373
	if (iname)
1374
	    TRACE_(olerelay)("%s:",relaystr(iname));
1375
	if (fname)
1376
	    TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1377
	else
1378 1379
	    TRACE_(olerelay)("%d",method);
	TRACE_(olerelay)("(");
1380
    }
1381

1382 1383
    SysFreeString(iname);
    SysFreeString(fname);
1384 1385 1386 1387 1388

    memset(&buf,0,sizeof(buf));

    /* normal typelib driven serializing */

1389 1390
    /* Need them for hack below */
    memset(names,0,sizeof(names));
1391
    if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1392 1393
	nrofnames = 0;
    if (nrofnames > sizeof(names)/sizeof(names[0]))
1394
	ERR("Need more names!\n");
1395

1396 1397 1398 1399 1400 1401 1402 1403 1404
    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. */
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
        if (!is_in_elem(elem))
        {
            if (elem->tdesc.vt != VT_PTR)
            {
                xargs+=_argsize(&elem->tdesc, tinfo);
                if (relaydeb) TRACE_(olerelay)("[out]");
                continue;
            }
            else
            {
                memset( *(void **)xargs, 0, _xsize( elem->tdesc.u.lptdesc, tinfo ) );
            }
        }

1419 1420
	hres = serialize_param(
	    tinfo,
1421
	    is_in_elem(elem),
1422 1423 1424 1425 1426 1427
	    relaydeb,
	    FALSE,
	    &elem->tdesc,
	    xargs,
	    &buf
	);
1428 1429

	if (hres) {
1430
	    ERR("Failed to serialize param, hres %x\n",hres);
1431 1432
	    break;
	}
1433
	xargs+=_argsize(&elem->tdesc, tinfo);
1434
    }
1435
    if (relaydeb) TRACE_(olerelay)(")");
1436

1437 1438 1439
    memset(&msg,0,sizeof(msg));
    msg.cbBuffer = buf.curoff;
    msg.iMethod  = method;
1440
    hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1441
    if (hres) {
1442
	ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1443
	goto exit;
1444 1445
    }
    memcpy(msg.Buffer,buf.base,buf.curoff);
1446
    if (relaydeb) TRACE_(olerelay)("\n");
1447
    hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1448
    if (hres) {
1449
	ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1450
	goto exit;
1451
    }
1452

1453
    if (relaydeb) TRACE_(olerelay)(" status = %08x (",status);
1454 1455 1456 1457 1458 1459 1460
    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;
1461 1462 1463

    /* generic deserializer using typelib description */
    xargs = args;
1464
    status = S_OK;
1465 1466 1467 1468 1469 1470 1471 1472
    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 */
1473
	if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1474
	    xargs += _argsize(&elem->tdesc, tinfo);
1475 1476 1477
	    if (relaydeb) TRACE_(olerelay)("[in]");
	    continue;
	}
1478 1479
	hres = deserialize_param(
	    tinfo,
1480
	    is_out_elem(elem),
1481 1482 1483 1484 1485 1486
	    relaydeb,
	    FALSE,
	    &(elem->tdesc),
	    xargs,
	    &buf
        );
1487
	if (hres) {
1488
	    ERR("Failed to unmarshall param, hres %x\n",hres);
1489 1490 1491
	    status = hres;
	    break;
	}
1492
	xargs += _argsize(&elem->tdesc, tinfo);
1493
    }
1494

1495 1496
    hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
    if (hres != S_OK)
1497
        goto exit;
1498
    if (relaydeb) TRACE_(olerelay)(") = %08x\n", remoteresult);
1499

1500
    hres = remoteresult;
1501

1502
exit:
1503
    IRpcChannelBuffer_FreeBuffer(chanbuf,&msg);
1504 1505
    for (i = 0; i < nrofnames; i++)
        SysFreeString(names[i]);
1506
    HeapFree(GetProcessHeap(),0,buf.base);
1507
    IRpcChannelBuffer_Release(chanbuf);
1508
    ITypeInfo_Release(tinfo);
1509
    TRACE("-- 0x%08x\n", hres);
1510
    return hres;
1511 1512
}

1513
static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
{
    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;
}

1526
static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
{
    TMProxyImpl *proxy = (TMProxyImpl *)iface;

    TRACE("\n");

    if (proxy->outerunknown)
        return IUnknown_AddRef(proxy->outerunknown);

    return 2; /* FIXME */
}

1538
static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
{
    TMProxyImpl *proxy = (TMProxyImpl *)iface;

    TRACE("\n");

    if (proxy->outerunknown)
        return IUnknown_Release(proxy->outerunknown);

    return 1; /* FIXME */
}

1550 1551 1552 1553 1554 1555
static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
{
    TMProxyImpl *This = (TMProxyImpl *)iface;

    TRACE("(%p)\n", pctinfo);

1556
    return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1557 1558 1559 1560 1561 1562
}

static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
{
    TMProxyImpl *This = (TMProxyImpl *)iface;

1563
    TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1564

1565
    return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1566 1567 1568 1569 1570 1571
}

static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
{
    TMProxyImpl *This = (TMProxyImpl *)iface;

1572
    TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1573

1574 1575
    return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
                                   cNames, lcid, rgDispId);
1576 1577 1578 1579 1580 1581 1582 1583
}

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;

1584
    TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1585 1586
          debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
          pExcepInfo, puArgErr);
1587

1588 1589 1590 1591
    return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
                            wFlags, pDispParams, pVarResult, pExcepInfo,
                            puArgErr);
}
1592

1593 1594
typedef struct
{
1595
    IRpcChannelBuffer     IRpcChannelBuffer_iface;
1596 1597
    LONG                  refs;
    /* the IDispatch-derived interface we are handling */
1598
    IID                   tmarshal_iid;
1599 1600 1601
    IRpcChannelBuffer    *pDelegateChannel;
} TMarshalDispatchChannel;

1602 1603 1604 1605 1606
static inline TMarshalDispatchChannel *impl_from_IRpcChannelBuffer(IRpcChannelBuffer *iface)
{
    return CONTAINING_RECORD(iface, TMarshalDispatchChannel, IRpcChannelBuffer_iface);
}

1607 1608 1609 1610 1611
static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
{
    *ppv = NULL;
    if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
    {
1612
        *ppv = iface;
1613 1614 1615 1616 1617 1618 1619 1620
        IUnknown_AddRef(iface);
        return S_OK;
    }
    return E_NOINTERFACE;
}

static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
{
1621
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1622 1623 1624 1625 1626
    return InterlockedIncrement(&This->refs);
}

static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
{
1627
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
    ULONG ref;

    ref = InterlockedDecrement(&This->refs);
    if (ref)
        return ref;

	IRpcChannelBuffer_Release(This->pDelegateChannel);
    HeapFree(GetProcessHeap(), 0, This);
    return 0;
}

static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
{
1641
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1642 1643 1644 1645 1646 1647 1648 1649 1650
    TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
    /* Note: we are pretending to invoke a method on the interface identified
     * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
     * without the RPC runtime getting confused by not exporting an IDispatch interface */
    return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
}

static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
{
1651
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1652 1653 1654 1655 1656 1657
    TRACE("(%p, %p)\n", olemsg, pstatus);
    return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
}

static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
{
1658
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1659 1660 1661 1662 1663 1664
    TRACE("(%p)\n", olemsg);
    return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
}

static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
{
1665
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1666 1667 1668 1669 1670 1671
    TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
    return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
}

static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
{
1672
    TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
    TRACE("()\n");
    return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
}

static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
{
    TMarshalDispatchChannel_QueryInterface,
    TMarshalDispatchChannel_AddRef,
    TMarshalDispatchChannel_Release,
    TMarshalDispatchChannel_GetBuffer,
    TMarshalDispatchChannel_SendReceive,
    TMarshalDispatchChannel_FreeBuffer,
    TMarshalDispatchChannel_GetDestCtx,
    TMarshalDispatchChannel_IsConnected
};

static HRESULT TMarshalDispatchChannel_Create(
    IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
    IRpcChannelBuffer **ppChannel)
{
    TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
    if (!This)
        return E_OUTOFMEMORY;

1697
    This->IRpcChannelBuffer_iface.lpVtbl = &TMarshalDispatchChannelVtbl;
1698 1699 1700 1701 1702
    This->refs = 1;
    IRpcChannelBuffer_AddRef(pDelegateChannel);
    This->pDelegateChannel = pDelegateChannel;
    This->tmarshal_iid = *tmarshal_riid;

1703
    *ppChannel = &This->IRpcChannelBuffer_iface;
1704 1705 1706 1707
    return S_OK;
}


1708 1709 1710 1711 1712 1713 1714 1715 1716
static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
{
    HRESULT       hr;
    CLSID         clsid;

    if ((hr = CoGetPSClsid(riid, &clsid)))
        return hr;
    return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
                             &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1717 1718
}

1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
{
    int j;
    /* nrofargs without This */
    int nrofargs;
    ITypeInfo *tinfo2;
    TMAsmProxy	*xasm = proxy->asmstubs + num;
    HRESULT hres;
    const FUNCDESC *fdesc;

    hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
    if (hres) {
        ERR("GetFuncDesc %x should not fail here.\n",hres);
        return hres;
    }
    ITypeInfo_Release(tinfo2);
    /* some args take more than 4 byte on the stack */
    nrofargs = 0;
    for (j=0;j<fdesc->cParams;j++)
1738
        nrofargs += _argsize(&fdesc->lprgelemdescParam[j].tdesc, proxy->tinfo);
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754

#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;
1755
    xasm->pushlval      = 0x68;
1756 1757 1758 1759 1760 1761 1762
    xasm->nr            = num;
    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 */
1763
    xasm->nop           = 0x90;
1764
    proxy->lpvtbl[fdesc->oVft / sizeof(void *)] = xasm;
1765 1766 1767 1768 1769 1770 1771
#else
    FIXME("not implemented on non i386\n");
    return E_FAIL;
#endif
    return S_OK;
}

1772 1773 1774
static HRESULT WINAPI
PSFacBuf_CreateProxy(
    LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1775 1776
    IRpcProxyBuffer **ppProxy, LPVOID *ppv)
{
1777 1778
    HRESULT	hres;
    ITypeInfo	*tinfo;
1779
    unsigned int i, nroffuncs, vtbl_size;
1780
    TMProxyImpl	*proxy;
1781
    TYPEATTR	*typeattr;
1782
    BOOL        defer_to_dispatch = FALSE;
1783

1784 1785 1786
    TRACE("(...%s...)\n",debugstr_guid(riid));
    hres = _get_typeinfo_for_iid(riid,&tinfo);
    if (hres) {
1787
	ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1788 1789
	return hres;
    }
1790

1791 1792 1793
    hres = num_of_funcs(tinfo, &nroffuncs, &vtbl_size);
    TRACE("Got %d funcs, vtbl size %d\n", nroffuncs, vtbl_size);

1794 1795 1796 1797 1798 1799
    if (FAILED(hres)) {
        ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
        ITypeInfo_Release(tinfo);
        return hres;
    }

1800
    proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1801 1802
    if (!proxy) return E_OUTOFMEMORY;

1803
    assert(sizeof(TMAsmProxy) == 16);
1804

1805
    proxy->dispatch = NULL;
1806
    proxy->dispatch_proxy = NULL;
1807
    proxy->outerunknown = pUnkOuter;
1808 1809 1810
    proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!proxy->asmstubs) {
        ERR("Could not commit pages for proxy thunks\n");
1811
        CoTaskMemFree(proxy);
1812 1813
        return E_OUTOFMEMORY;
    }
1814
    proxy->IRpcProxyBuffer_iface.lpVtbl = &tmproxyvtable;
1815 1816 1817
    /* one reference for the proxy */
    proxy->ref		= 1;
    proxy->tinfo	= tinfo;
1818
    proxy->iid		= *riid;
1819
    proxy->chanbuf      = 0;
1820

1821
    InitializeCriticalSection(&proxy->crit);
1822
    proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
1823

1824
    proxy->lpvtbl = HeapAlloc(GetProcessHeap(), 0, vtbl_size);
1825 1826 1827 1828 1829 1830 1831

    /* 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)
        {
1832 1833 1834 1835 1836 1837 1838 1839 1840
            IPSFactoryBuffer *factory_buffer;
            hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
            if (hres == S_OK)
            {
                hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
                    &IID_IDispatch, &proxy->dispatch_proxy,
                    (void **)&proxy->dispatch);
                IPSFactoryBuffer_Release(factory_buffer);
            }
1841 1842 1843 1844 1845
            if ((hres == S_OK) && (nroffuncs < 7))
            {
                ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
                hres = E_UNEXPECTED;
            }
1846 1847
            if (hres == S_OK)
            {
1848
                defer_to_dispatch = TRUE;
1849
            }
1850 1851 1852 1853
        }
        ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
    }

1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
    for (i=0;i<nroffuncs;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;
        case 3:
                if(!defer_to_dispatch)
                {
                    hres = init_proxy_entry_point(proxy, i);
                    if(FAILED(hres)) return hres;
                }
                else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
                break;
        case 4:
                if(!defer_to_dispatch)
                {
                    hres = init_proxy_entry_point(proxy, i);
                    if(FAILED(hres)) return hres;
                }
                else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
                break;
        case 5:
                if(!defer_to_dispatch)
                {
                    hres = init_proxy_entry_point(proxy, i);
                    if(FAILED(hres)) return hres;
                }
                else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
                break;
        case 6:
                if(!defer_to_dispatch)
                {
                    hres = init_proxy_entry_point(proxy, i);
                    if(FAILED(hres)) return hres;
                }
                else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
                break;
	default:
                hres = init_proxy_entry_point(proxy, i);
                if(FAILED(hres)) return hres;
	}
    }

1903 1904
    if (hres == S_OK)
    {
1905
        *ppv = proxy;
1906
        *ppProxy = &proxy->IRpcProxyBuffer_iface;
1907 1908 1909 1910
        IUnknown_AddRef((IUnknown *)*ppv);
        return S_OK;
    }
    else
1911
        TMProxyImpl_Release(&proxy->IRpcProxyBuffer_iface);
1912
    return hres;
1913 1914 1915
}

typedef struct _TMStubImpl {
1916
    IRpcStubBuffer              IRpcStubBuffer_iface;
1917
    LONG			ref;
1918 1919 1920 1921

    LPUNKNOWN			pUnk;
    ITypeInfo			*tinfo;
    IID				iid;
1922
    IRpcStubBuffer		*dispatch_stub;
1923
    BOOL			dispatch_derivative;
1924 1925
} TMStubImpl;

1926 1927 1928 1929 1930
static inline TMStubImpl *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
{
    return CONTAINING_RECORD(iface, TMStubImpl, IRpcStubBuffer_iface);
}

1931
static HRESULT WINAPI
1932 1933
TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
{
1934
    if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1935
        *ppv = iface;
1936 1937 1938 1939 1940 1941 1942 1943
	IRpcStubBuffer_AddRef(iface);
	return S_OK;
    }
    FIXME("%s, not supported IID.\n",debugstr_guid(riid));
    return E_NOINTERFACE;
}

static ULONG WINAPI
1944 1945
TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
{
1946
    TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1947
    ULONG refCount = InterlockedIncrement(&This->ref);
1948

1949
    TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
1950

1951
    return refCount;
1952 1953 1954
}

static ULONG WINAPI
1955 1956
TMStubImpl_Release(LPRPCSTUBBUFFER iface)
{
1957
    TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1958
    ULONG refCount = InterlockedDecrement(&This->ref);
1959

1960
    TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
1961

1962
    if (!refCount)
1963 1964
    {
        IRpcStubBuffer_Disconnect(iface);
1965
        ITypeInfo_Release(This->tinfo);
1966 1967
        if (This->dispatch_stub)
            IRpcStubBuffer_Release(This->dispatch_stub);
1968 1969
        CoTaskMemFree(This);
    }
1970
    return refCount;
1971 1972 1973
}

static HRESULT WINAPI
1974 1975
TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
{
1976
    TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1977

1978 1979
    TRACE("(%p)->(%p)\n", This, pUnkServer);

1980 1981
    IUnknown_AddRef(pUnkServer);
    This->pUnk = pUnkServer;
1982 1983 1984 1985

    if (This->dispatch_stub)
        IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);

1986 1987 1988 1989
    return S_OK;
}

static void WINAPI
1990 1991
TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
{
1992
    TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1993

1994 1995
    TRACE("(%p)->()\n", This);

1996 1997 1998 1999 2000
    if (This->pUnk)
    {
        IUnknown_Release(This->pUnk);
        This->pUnk = NULL;
    }
2001 2002 2003

    if (This->dispatch_stub)
        IRpcStubBuffer_Disconnect(This->dispatch_stub);
2004 2005 2006 2007
}

static HRESULT WINAPI
TMStubImpl_Invoke(
2008 2009
    LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
{
2010
#ifdef __i386__
2011
    int		i;
2012
    const FUNCDESC *fdesc;
2013
    TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2014
    HRESULT	hres;
2015
    DWORD	*args = NULL, res, *xargs, nrofargs;
2016
    marshal_state	buf;
2017
    UINT	nrofnames = 0;
2018
    BSTR	names[10];
2019
    BSTR	iname = NULL;
2020
    ITypeInfo 	*tinfo = NULL;
2021 2022

    TRACE("...\n");
2023 2024 2025 2026

    if (xmsg->iMethod < 3) {
        ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
        return E_UNEXPECTED;
2027
    }
2028

2029 2030
    if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
    {
2031
        if (!This->dispatch_stub)
2032
        {
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042
            IPSFactoryBuffer *factory_buffer;
            hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
            if (hres == S_OK)
            {
                hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
                    This->pUnk, &This->dispatch_stub);
                IPSFactoryBuffer_Release(factory_buffer);
            }
            if (hres != S_OK)
                return hres;
2043
        }
2044
        return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
2045
    }
2046 2047 2048 2049 2050 2051 2052

    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;

2053
    hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
2054
    if (hres) {
2055
	ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
2056 2057
	return hres;
    }
2058

2059 2060 2061
    if (iname && !lstrcmpW(iname, IDispatchW))
    {
        ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
2062 2063 2064
        hres = E_UNEXPECTED;
        SysFreeString (iname);
        goto exit;
2065
    }
2066

2067
    SysFreeString (iname);
2068

2069 2070
    /* Need them for hack below */
    memset(names,0,sizeof(names));
2071
    ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
2072 2073 2074 2075 2076 2077 2078
    if (nrofnames > sizeof(names)/sizeof(names[0])) {
	ERR("Need more names!\n");
    }

    /*dump_FUNCDESC(fdesc);*/
    nrofargs = 0;
    for (i=0;i<fdesc->cParams;i++)
2079
	nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo);
2080
    args = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(nrofargs+1)*sizeof(DWORD));
2081 2082 2083 2084 2085
    if (!args)
    {
        hres = E_OUTOFMEMORY;
        goto exit;
    }
2086 2087 2088 2089 2090

    /* Allocate all stuff used by call. */
    xargs = args+1;
    for (i=0;i<fdesc->cParams;i++) {
	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
2091

2092 2093
	hres = deserialize_param(
	   tinfo,
2094
	   is_in_elem(elem),
2095 2096 2097 2098 2099 2100
	   FALSE,
	   TRUE,
	   &(elem->tdesc),
	   xargs,
	   &buf
	);
2101
	xargs += _argsize(&elem->tdesc, tinfo);
2102
	if (hres) {
2103
	    ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2104 2105 2106
	    break;
	}
    }
2107

2108
    args[0] = (DWORD)This->pUnk;
2109 2110 2111 2112 2113 2114 2115 2116 2117 2118

    __TRY
    {
        res = _invoke(
            (*((FARPROC**)args[0]))[fdesc->oVft/4],
            fdesc->callconv,
            (xargs-args),
            args
        );
    }
2119
    __EXCEPT_ALL
2120 2121
    {
        DWORD dwExceptionCode = GetExceptionCode();
2122
        ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2123 2124 2125 2126 2127 2128 2129 2130
        if (FAILED(dwExceptionCode))
            hres = dwExceptionCode;
        else
            hres = HRESULT_FROM_WIN32(dwExceptionCode);
    }
    __ENDTRY

    if (hres != S_OK)
2131
        goto exit;
2132

2133
    buf.curoff = 0;
2134

2135 2136 2137
    xargs = args+1;
    for (i=0;i<fdesc->cParams;i++) {
	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
2138 2139
	hres = serialize_param(
	   tinfo,
2140
	   is_out_elem(elem),
2141 2142 2143 2144 2145 2146
	   FALSE,
	   TRUE,
	   &elem->tdesc,
	   xargs,
	   &buf
	);
2147
	xargs += _argsize(&elem->tdesc, tinfo);
2148
	if (hres) {
2149
	    ERR("Failed to stuballoc param, hres %x\n",hres);
2150 2151 2152
	    break;
	}
    }
2153

2154
    hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2155

2156
    if (hres != S_OK)
2157
        goto exit;
2158

2159
    xmsg->cbBuffer	= buf.curoff;
2160 2161
    hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
    if (hres != S_OK)
2162
        ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2163 2164 2165 2166

    if (hres == S_OK)
        memcpy(xmsg->Buffer, buf.base, buf.curoff);

2167 2168 2169 2170 2171 2172 2173
exit:
    for (i = 0; i < nrofnames; i++)
        SysFreeString(names[i]);

    ITypeInfo_Release(tinfo);
    HeapFree(GetProcessHeap(), 0, args);

2174 2175 2176 2177
    HeapFree(GetProcessHeap(), 0, buf.base);

    TRACE("returning\n");
    return hres;
2178 2179 2180 2181
#else
    FIXME( "not implemented on non-i386\n" );
    return E_FAIL;
#endif
2182 2183 2184 2185 2186 2187 2188 2189 2190 2191
}

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) {
2192
    TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2193

2194
    FIXME("()\n");
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
    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;
}

2208
static const IRpcStubBufferVtbl tmstubvtbl = {
2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228
    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;
2229
    TYPEATTR *typeattr;
2230 2231

    TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2232

2233 2234
    hres = _get_typeinfo_for_iid(riid,&tinfo);
    if (hres) {
2235
	ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2236 2237
	return hres;
    }
2238

2239
    stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2240 2241
    if (!stub)
	return E_OUTOFMEMORY;
2242
    stub->IRpcStubBuffer_iface.lpVtbl = &tmstubvtbl;
2243 2244
    stub->ref		= 1;
    stub->tinfo		= tinfo;
2245
    stub->dispatch_stub = NULL;
2246
    stub->dispatch_derivative = FALSE;
2247
    stub->iid		= *riid;
2248 2249
    hres = IRpcStubBuffer_Connect(&stub->IRpcStubBuffer_iface,pUnkServer);
    *ppStub = &stub->IRpcStubBuffer_iface;
2250
    TRACE("IRpcStubBuffer: %p\n", stub);
2251
    if (hres)
2252
	ERR("Connect to pUnkServer failed?\n");
2253 2254 2255 2256 2257 2258

    /* if we derive from IDispatch then defer to its stub for some of its methods */
    hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
    if (hres == S_OK)
    {
        if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2259
            stub->dispatch_derivative = TRUE;
2260 2261 2262
        ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
    }

2263 2264 2265
    return hres;
}

2266
static const IPSFactoryBufferVtbl psfacbufvtbl = {
2267 2268 2269 2270 2271 2272 2273 2274
    PSFacBuf_QueryInterface,
    PSFacBuf_AddRef,
    PSFacBuf_Release,
    PSFacBuf_CreateProxy,
    PSFacBuf_CreateStub
};

/* This is the whole PSFactoryBuffer object, just the vtableptr */
2275
static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
2276 2277

/***********************************************************************
2278
 *           TMARSHAL_DllGetClassObject
2279
 */
2280
HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
2281 2282 2283 2284 2285 2286 2287
{
    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
	*ppv = &lppsfac;
	return S_OK;
    }
    return E_NOINTERFACE;
}