wined3d: Don't use the builtin FFP uniforms for the material.
[wine/multimedia.git] / dlls / oleaut32 / tmarshal.c
blob7bf62b7a0d8b2126c609ff0e8ad9cbb9c5155ce3
1 /*
2 * TYPELIB Marshaler
4 * Copyright 2002,2005 Marcus Meissner
6 * The olerelay debug channel allows you to see calls marshalled by
7 * the typelib marshaller. It is not a generic COM relaying system.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * 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
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <ctype.h>
34 #define COBJMACROS
35 #define NONAMELESSUNION
37 #include "winerror.h"
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winnls.h"
41 #include "winreg.h"
42 #include "winuser.h"
44 #include "ole2.h"
45 #include "propidl.h" /* for LPSAFEARRAY_User* functions */
46 #include "typelib.h"
47 #include "variant.h"
48 #include "wine/debug.h"
49 #include "wine/exception.h"
51 static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
56 static HRESULT TMarshalDispatchChannel_Create(
57 IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
58 IRpcChannelBuffer **ppChannel);
60 typedef struct _marshal_state {
61 LPBYTE base;
62 int size;
63 int curoff;
64 } marshal_state;
66 /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
67 static char *relaystr(WCHAR *in) {
68 char *tmp = (char *)debugstr_w(in);
69 tmp += 2;
70 tmp[strlen(tmp)-1] = '\0';
71 return tmp;
74 static HRESULT
75 xbuf_resize(marshal_state *buf, DWORD newsize)
77 if(buf->size >= newsize)
78 return S_FALSE;
80 if(buf->base)
82 buf->base = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf->base, newsize);
83 if(!buf->base)
84 return E_OUTOFMEMORY;
86 else
88 buf->base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
89 if(!buf->base)
90 return E_OUTOFMEMORY;
92 buf->size = newsize;
93 return S_OK;
96 static HRESULT
97 xbuf_add(marshal_state *buf, const BYTE *stuff, DWORD size)
99 HRESULT hr;
101 if(buf->size - buf->curoff < size)
103 hr = xbuf_resize(buf, buf->size + size + 100);
104 if(FAILED(hr)) return hr;
106 memcpy(buf->base+buf->curoff,stuff,size);
107 buf->curoff += size;
108 return S_OK;
111 static HRESULT
112 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
113 if (buf->size < buf->curoff+size) return E_FAIL;
114 memcpy(stuff,buf->base+buf->curoff,size);
115 buf->curoff += size;
116 return S_OK;
119 static HRESULT
120 xbuf_skip(marshal_state *buf, DWORD size) {
121 if (buf->size < buf->curoff+size) return E_FAIL;
122 buf->curoff += size;
123 return S_OK;
126 static HRESULT
127 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
128 IStream *pStm;
129 ULARGE_INTEGER newpos;
130 LARGE_INTEGER seekto;
131 ULONG res;
132 HRESULT hres;
133 DWORD xsize;
135 TRACE("...%s...\n",debugstr_guid(riid));
137 *pUnk = NULL;
138 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
139 if (hres) {
140 ERR("xbuf_get failed\n");
141 return hres;
144 if (xsize == 0) return S_OK;
146 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
147 if (hres) {
148 ERR("Stream create failed %x\n",hres);
149 return hres;
152 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
153 if (hres) {
154 ERR("stream write %x\n",hres);
155 IStream_Release(pStm);
156 return hres;
159 memset(&seekto,0,sizeof(seekto));
160 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
161 if (hres) {
162 ERR("Failed Seek %x\n",hres);
163 IStream_Release(pStm);
164 return hres;
167 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
168 if (hres) {
169 ERR("Unmarshalling interface %s failed with %x\n",debugstr_guid(riid),hres);
170 IStream_Release(pStm);
171 return hres;
174 IStream_Release(pStm);
175 return xbuf_skip(buf,xsize);
178 static HRESULT
179 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
180 LPBYTE tempbuf = NULL;
181 IStream *pStm = NULL;
182 STATSTG ststg;
183 ULARGE_INTEGER newpos;
184 LARGE_INTEGER seekto;
185 ULONG res;
186 DWORD xsize;
187 HRESULT hres;
189 if (!pUnk) {
190 /* this is valid, if for instance we serialize
191 * a VT_DISPATCH with NULL ptr which apparently
192 * can happen. S_OK to make sure we continue
193 * serializing.
195 WARN("pUnk is NULL\n");
196 xsize = 0;
197 return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
200 TRACE("...%s...\n",debugstr_guid(riid));
202 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
203 if (hres) {
204 ERR("Stream create failed %x\n",hres);
205 goto fail;
208 hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
209 if (hres) {
210 ERR("Marshalling interface %s failed with %x\n", debugstr_guid(riid), hres);
211 goto fail;
214 hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
215 if (hres) {
216 ERR("Stream stat failed\n");
217 goto fail;
220 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
221 memset(&seekto,0,sizeof(seekto));
222 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
223 if (hres) {
224 ERR("Failed Seek %x\n",hres);
225 goto fail;
228 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
229 if (hres) {
230 ERR("Failed Read %x\n",hres);
231 goto fail;
234 xsize = ststg.cbSize.u.LowPart;
235 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
236 hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
238 HeapFree(GetProcessHeap(),0,tempbuf);
239 IStream_Release(pStm);
241 return hres;
243 fail:
244 xsize = 0;
245 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
246 if (pStm) IStream_Release(pStm);
247 HeapFree(GetProcessHeap(), 0, tempbuf);
248 return hres;
251 /********************* OLE Proxy/Stub Factory ********************************/
252 static HRESULT WINAPI
253 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
254 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
255 *ppv = iface;
256 /* No ref counting, static class */
257 return S_OK;
259 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
260 return E_NOINTERFACE;
263 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
264 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
266 static HRESULT
267 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
268 HRESULT hres;
269 HKEY ikey;
270 REGSAM opposite = (sizeof(void*) == 8) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
271 BOOL is_wow64;
272 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
273 char tlfn[260];
274 OLECHAR tlfnW[260];
275 DWORD tlguidlen, verlen, type;
276 LONG tlfnlen, err;
277 ITypeLib *tl;
279 sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
280 riid->Data1, riid->Data2, riid->Data3,
281 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
282 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
285 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ,&ikey);
286 if (err && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64)
287 && is_wow64))) {
288 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ|opposite,&ikey);
290 if (err) {
291 ERR("No %s key found.\n",interfacekey);
292 return E_FAIL;
294 tlguidlen = sizeof(tlguid);
295 if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
296 ERR("Getting typelib guid failed.\n");
297 RegCloseKey(ikey);
298 return E_FAIL;
300 verlen = sizeof(ver);
301 if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
302 ERR("Could not get version value?\n");
303 RegCloseKey(ikey);
304 return E_FAIL;
306 RegCloseKey(ikey);
307 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win%u",tlguid,ver,(sizeof(void*) == 8) ? 64 : 32);
308 tlfnlen = sizeof(tlfn);
309 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
310 #ifdef _WIN64
311 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
312 tlfnlen = sizeof(tlfn);
313 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
314 #endif
315 ERR("Could not get typelib fn?\n");
316 return E_FAIL;
317 #ifdef _WIN64
319 #endif
321 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, sizeof(tlfnW) / sizeof(tlfnW[0]));
322 hres = LoadTypeLib(tlfnW,&tl);
323 if (hres) {
324 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
325 return hres;
327 hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
328 if (hres) {
329 ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
330 ITypeLib_Release(tl);
331 return hres;
333 ITypeLib_Release(tl);
334 return hres;
338 * Determine the number of functions including all inherited functions
339 * and well as the size of the vtbl.
340 * Note for non-dual dispinterfaces we simply return the size of IDispatch.
342 static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num,
343 unsigned int *vtbl_size)
345 HRESULT hr;
346 TYPEATTR *attr;
347 ITypeInfo *tinfo2;
348 UINT inherited_funcs = 0, i;
350 *num = 0;
351 if(vtbl_size) *vtbl_size = 0;
353 hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
354 if (hr)
356 ERR("GetTypeAttr failed with %x\n", hr);
357 return hr;
360 if(attr->typekind == TKIND_DISPATCH)
362 if(attr->wTypeFlags & TYPEFLAG_FDUAL)
364 HREFTYPE href;
366 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
367 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
368 if(FAILED(hr))
370 ERR("Unable to get interface href from dual dispinterface\n");
371 return hr;
373 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
374 if(FAILED(hr))
376 ERR("Unable to get interface from dual dispinterface\n");
377 return hr;
379 hr = num_of_funcs(tinfo2, num, vtbl_size);
380 ITypeInfo_Release(tinfo2);
381 return hr;
383 else /* non-dual dispinterface */
385 /* These will be the size of IDispatchVtbl */
386 *num = attr->cbSizeVft / sizeof(void *);
387 if(vtbl_size) *vtbl_size = attr->cbSizeVft;
388 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
389 return hr;
393 for (i = 0; i < attr->cImplTypes; i++)
395 HREFTYPE href;
396 ITypeInfo *pSubTypeInfo;
397 UINT sub_funcs;
399 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
400 if (FAILED(hr)) goto end;
401 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
402 if (FAILED(hr)) goto end;
404 hr = num_of_funcs(pSubTypeInfo, &sub_funcs, NULL);
405 ITypeInfo_Release(pSubTypeInfo);
407 if(FAILED(hr)) goto end;
408 inherited_funcs += sub_funcs;
411 *num = inherited_funcs + attr->cFuncs;
412 if(vtbl_size) *vtbl_size = attr->cbSizeVft;
414 end:
415 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
416 return hr;
419 #ifdef __i386__
421 #include "pshpack1.h"
423 typedef struct _TMAsmProxy {
424 DWORD lealeax;
425 BYTE pushleax;
426 BYTE pushlval;
427 DWORD nr;
428 BYTE lcall;
429 DWORD xcall;
430 BYTE lret;
431 WORD bytestopop;
432 WORD nop;
433 } TMAsmProxy;
435 #include "poppack.h"
437 #else /* __i386__ */
438 # warning You need to implement stubless proxies for your architecture
439 typedef struct _TMAsmProxy {
440 } TMAsmProxy;
441 #endif
443 typedef struct _TMProxyImpl {
444 LPVOID *lpvtbl;
445 IRpcProxyBuffer IRpcProxyBuffer_iface;
446 LONG ref;
448 TMAsmProxy *asmstubs;
449 ITypeInfo* tinfo;
450 IRpcChannelBuffer* chanbuf;
451 IID iid;
452 CRITICAL_SECTION crit;
453 IUnknown *outerunknown;
454 IDispatch *dispatch;
455 IRpcProxyBuffer *dispatch_proxy;
456 } TMProxyImpl;
458 static inline TMProxyImpl *impl_from_IRpcProxyBuffer( IRpcProxyBuffer *iface )
460 return CONTAINING_RECORD(iface, TMProxyImpl, IRpcProxyBuffer_iface);
463 static HRESULT WINAPI
464 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
466 TRACE("()\n");
467 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
468 *ppv = iface;
469 IRpcProxyBuffer_AddRef(iface);
470 return S_OK;
472 FIXME("no interface for %s\n",debugstr_guid(riid));
473 return E_NOINTERFACE;
476 static ULONG WINAPI
477 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
479 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
480 ULONG refCount = InterlockedIncrement(&This->ref);
482 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
484 return refCount;
487 static ULONG WINAPI
488 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
490 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
491 ULONG refCount = InterlockedDecrement(&This->ref);
493 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
495 if (!refCount)
497 if (This->dispatch_proxy) IRpcProxyBuffer_Release(This->dispatch_proxy);
498 This->crit.DebugInfo->Spare[0] = 0;
499 DeleteCriticalSection(&This->crit);
500 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
501 VirtualFree(This->asmstubs, 0, MEM_RELEASE);
502 HeapFree(GetProcessHeap(), 0, This->lpvtbl);
503 ITypeInfo_Release(This->tinfo);
504 CoTaskMemFree(This);
506 return refCount;
509 static HRESULT WINAPI
510 TMProxyImpl_Connect(
511 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
513 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
515 TRACE("(%p)\n", pRpcChannelBuffer);
517 EnterCriticalSection(&This->crit);
519 IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
520 This->chanbuf = pRpcChannelBuffer;
522 LeaveCriticalSection(&This->crit);
524 if (This->dispatch_proxy)
526 IRpcChannelBuffer *pDelegateChannel;
527 HRESULT hr = TMarshalDispatchChannel_Create(pRpcChannelBuffer, &This->iid, &pDelegateChannel);
528 if (FAILED(hr))
529 return hr;
530 hr = IRpcProxyBuffer_Connect(This->dispatch_proxy, pDelegateChannel);
531 IRpcChannelBuffer_Release(pDelegateChannel);
532 return hr;
535 return S_OK;
538 static void WINAPI
539 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
541 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
543 TRACE("()\n");
545 EnterCriticalSection(&This->crit);
547 IRpcChannelBuffer_Release(This->chanbuf);
548 This->chanbuf = NULL;
550 LeaveCriticalSection(&This->crit);
552 if (This->dispatch_proxy)
553 IRpcProxyBuffer_Disconnect(This->dispatch_proxy);
557 static const IRpcProxyBufferVtbl tmproxyvtable = {
558 TMProxyImpl_QueryInterface,
559 TMProxyImpl_AddRef,
560 TMProxyImpl_Release,
561 TMProxyImpl_Connect,
562 TMProxyImpl_Disconnect
565 /* how much space do we use on stack in DWORD steps. */
566 static int
567 _argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
568 switch (tdesc->vt) {
569 case VT_I8:
570 case VT_UI8:
571 return 8/sizeof(DWORD);
572 case VT_R8:
573 return sizeof(double)/sizeof(DWORD);
574 case VT_CY:
575 return sizeof(CY)/sizeof(DWORD);
576 case VT_DATE:
577 return sizeof(DATE)/sizeof(DWORD);
578 case VT_DECIMAL:
579 return (sizeof(DECIMAL)+3)/sizeof(DWORD);
580 case VT_VARIANT:
581 return (sizeof(VARIANT)+3)/sizeof(DWORD);
582 case VT_USERDEFINED:
584 ITypeInfo *tinfo2;
585 TYPEATTR *tattr;
586 HRESULT hres;
587 DWORD ret;
589 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
590 if (FAILED(hres))
591 return 0; /* should fail critically in serialize_param */
592 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
593 ret = (tattr->cbSizeInstance+3)/sizeof(DWORD);
594 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
595 ITypeInfo_Release(tinfo2);
596 return ret;
598 default:
599 return 1;
603 /* how much space do we use on the heap (in bytes) */
604 static int
605 _xsize(const TYPEDESC *td, ITypeInfo *tinfo) {
606 switch (td->vt) {
607 case VT_DATE:
608 return sizeof(DATE);
609 case VT_CY:
610 return sizeof(CY);
611 case VT_VARIANT:
612 return sizeof(VARIANT);
613 case VT_CARRAY: {
614 int i, arrsize = 1;
615 const ARRAYDESC *adesc = td->u.lpadesc;
617 for (i=0;i<adesc->cDims;i++)
618 arrsize *= adesc->rgbounds[i].cElements;
619 return arrsize*_xsize(&adesc->tdescElem, tinfo);
621 case VT_UI8:
622 case VT_I8:
623 case VT_R8:
624 return 8;
625 case VT_UI2:
626 case VT_I2:
627 case VT_BOOL:
628 return 2;
629 case VT_UI1:
630 case VT_I1:
631 return 1;
632 case VT_USERDEFINED:
634 ITypeInfo *tinfo2;
635 TYPEATTR *tattr;
636 HRESULT hres;
637 DWORD ret;
639 hres = ITypeInfo_GetRefTypeInfo(tinfo,td->u.hreftype,&tinfo2);
640 if (FAILED(hres))
641 return 0;
642 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
643 ret = tattr->cbSizeInstance;
644 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
645 ITypeInfo_Release(tinfo2);
646 return ret;
648 default:
649 return 4;
653 /* Whether we pass this type by reference or by value */
654 static BOOL
655 _passbyref(const TYPEDESC *td, ITypeInfo *tinfo) {
656 return (td->vt == VT_USERDEFINED ||
657 td->vt == VT_VARIANT ||
658 td->vt == VT_PTR);
661 static HRESULT
662 serialize_param(
663 ITypeInfo *tinfo,
664 BOOL writeit,
665 BOOL debugout,
666 BOOL dealloc,
667 TYPEDESC *tdesc,
668 DWORD *arg,
669 marshal_state *buf)
671 HRESULT hres = S_OK;
672 VARTYPE vartype;
674 TRACE("(tdesc.vt %s)\n",debugstr_vt(tdesc->vt));
676 vartype = tdesc->vt;
677 if ((vartype & 0xf000) == VT_ARRAY)
678 vartype = VT_SAFEARRAY;
680 switch (vartype) {
681 case VT_DATE:
682 case VT_I8:
683 case VT_UI8:
684 case VT_R8:
685 case VT_CY:
686 hres = S_OK;
687 if (debugout) TRACE_(olerelay)("%x%x\n",arg[0],arg[1]);
688 if (writeit)
689 hres = xbuf_add(buf,(LPBYTE)arg,8);
690 return hres;
691 case VT_ERROR:
692 case VT_INT:
693 case VT_UINT:
694 case VT_I4:
695 case VT_R4:
696 case VT_UI4:
697 hres = S_OK;
698 if (debugout) TRACE_(olerelay)("%x\n",*arg);
699 if (writeit)
700 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
701 return hres;
702 case VT_I2:
703 case VT_UI2:
704 case VT_BOOL:
705 hres = S_OK;
706 if (debugout) TRACE_(olerelay)("%04x\n",*arg & 0xffff);
707 if (writeit)
708 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
709 return hres;
710 case VT_I1:
711 case VT_UI1:
712 hres = S_OK;
713 if (debugout) TRACE_(olerelay)("%02x\n",*arg & 0xff);
714 if (writeit)
715 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
716 return hres;
717 case VT_VARIANT: {
718 if (debugout) TRACE_(olerelay)("%s", debugstr_variant((VARIANT *)arg));
719 if (writeit)
721 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
722 ULONG size = VARIANT_UserSize(&flags, buf->curoff, (VARIANT *)arg);
723 xbuf_resize(buf, size);
724 VARIANT_UserMarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
725 buf->curoff = size;
727 if (dealloc)
729 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
730 VARIANT_UserFree(&flags, (VARIANT *)arg);
732 return S_OK;
734 case VT_BSTR: {
735 if (writeit && debugout) {
736 if (*arg)
737 TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
738 else
739 TRACE_(olerelay)("<bstr NULL>");
741 if (writeit)
743 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
744 ULONG size = BSTR_UserSize(&flags, buf->curoff, (BSTR *)arg);
745 xbuf_resize(buf, size);
746 BSTR_UserMarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
747 buf->curoff = size;
749 if (dealloc)
751 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
752 BSTR_UserFree(&flags, (BSTR *)arg);
754 return S_OK;
756 case VT_PTR: {
757 DWORD cookie;
758 BOOL derefhere = TRUE;
760 if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
761 ITypeInfo *tinfo2;
762 TYPEATTR *tattr;
764 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
765 if (hres) {
766 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
767 return hres;
769 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
770 switch (tattr->typekind) {
771 case TKIND_ALIAS:
772 if (tattr->tdescAlias.vt == VT_USERDEFINED)
774 DWORD href = tattr->tdescAlias.u.hreftype;
775 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
776 ITypeInfo_Release(tinfo2);
777 hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
778 if (hres) {
779 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
780 return hres;
782 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
783 derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
785 break;
786 case TKIND_ENUM: /* confirmed */
787 case TKIND_RECORD: /* FIXME: mostly untested */
788 break;
789 case TKIND_DISPATCH: /* will be done in VT_USERDEFINED case */
790 case TKIND_INTERFACE: /* will be done in VT_USERDEFINED case */
791 derefhere=FALSE;
792 break;
793 default:
794 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
795 derefhere=FALSE;
796 break;
798 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
799 ITypeInfo_Release(tinfo2);
802 if (debugout) TRACE_(olerelay)("*");
803 /* Write always, so the other side knows when it gets a NULL pointer.
805 cookie = *arg ? 0x42424242 : 0;
806 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
807 if (hres)
808 return hres;
809 if (!*arg) {
810 if (debugout) TRACE_(olerelay)("NULL");
811 return S_OK;
813 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
814 if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
815 return hres;
817 case VT_UNKNOWN:
818 if (debugout) TRACE_(olerelay)("unk(0x%x)",*arg);
819 if (writeit)
820 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
821 if (dealloc && *(IUnknown **)arg)
822 IUnknown_Release((LPUNKNOWN)*arg);
823 return hres;
824 case VT_DISPATCH:
825 if (debugout) TRACE_(olerelay)("idisp(0x%x)",*arg);
826 if (writeit)
827 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
828 if (dealloc && *(IUnknown **)arg)
829 IUnknown_Release((LPUNKNOWN)*arg);
830 return hres;
831 case VT_VOID:
832 if (debugout) TRACE_(olerelay)("<void>");
833 return S_OK;
834 case VT_USERDEFINED: {
835 ITypeInfo *tinfo2;
836 TYPEATTR *tattr;
838 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
839 if (hres) {
840 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
841 return hres;
843 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
844 switch (tattr->typekind) {
845 case TKIND_DISPATCH:
846 case TKIND_INTERFACE:
847 if (writeit)
848 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
849 if (dealloc)
850 IUnknown_Release((LPUNKNOWN)arg);
851 break;
852 case TKIND_RECORD: {
853 int i;
854 if (debugout) TRACE_(olerelay)("{");
855 for (i=0;i<tattr->cVars;i++) {
856 VARDESC *vdesc;
857 ELEMDESC *elem2;
858 TYPEDESC *tdesc2;
860 hres = ITypeInfo_GetVarDesc(tinfo2, i, &vdesc);
861 if (hres) {
862 ERR("Could not get vardesc of %d\n",i);
863 return hres;
865 elem2 = &vdesc->elemdescVar;
866 tdesc2 = &elem2->tdesc;
867 hres = serialize_param(
868 tinfo2,
869 writeit,
870 debugout,
871 dealloc,
872 tdesc2,
873 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
876 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
877 if (hres!=S_OK)
878 return hres;
879 if (debugout && (i<(tattr->cVars-1)))
880 TRACE_(olerelay)(",");
882 if (debugout) TRACE_(olerelay)("}");
883 break;
885 case TKIND_ALIAS:
886 hres = serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
887 break;
888 case TKIND_ENUM:
889 hres = S_OK;
890 if (debugout) TRACE_(olerelay)("%x",*arg);
891 if (writeit)
892 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
893 break;
894 default:
895 FIXME("Unhandled typekind %d\n",tattr->typekind);
896 hres = E_FAIL;
897 break;
899 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
900 ITypeInfo_Release(tinfo2);
901 return hres;
903 case VT_CARRAY: {
904 ARRAYDESC *adesc = tdesc->u.lpadesc;
905 int i, arrsize = 1;
907 if (debugout) TRACE_(olerelay)("carr");
908 for (i=0;i<adesc->cDims;i++) {
909 if (debugout) TRACE_(olerelay)("[%d]",adesc->rgbounds[i].cElements);
910 arrsize *= adesc->rgbounds[i].cElements;
912 if (debugout) TRACE_(olerelay)("(vt %s)",debugstr_vt(adesc->tdescElem.vt));
913 if (debugout) TRACE_(olerelay)("[");
914 for (i=0;i<arrsize;i++) {
915 LPBYTE base = _passbyref(&adesc->tdescElem, tinfo) ? (LPBYTE) *arg : (LPBYTE) arg;
916 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)base+i*_xsize(&adesc->tdescElem, tinfo)), buf);
917 if (hres)
918 return hres;
919 if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
921 if (debugout) TRACE_(olerelay)("]");
922 if (dealloc)
923 HeapFree(GetProcessHeap(), 0, *(void **)arg);
924 return S_OK;
926 case VT_SAFEARRAY: {
927 if (writeit)
929 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
930 ULONG size = LPSAFEARRAY_UserSize(&flags, buf->curoff, (LPSAFEARRAY *)arg);
931 xbuf_resize(buf, size);
932 LPSAFEARRAY_UserMarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
933 buf->curoff = size;
935 if (dealloc)
937 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
938 LPSAFEARRAY_UserFree(&flags, (LPSAFEARRAY *)arg);
940 return S_OK;
942 default:
943 ERR("Unhandled marshal type %d.\n",tdesc->vt);
944 return S_OK;
948 static HRESULT
949 deserialize_param(
950 ITypeInfo *tinfo,
951 BOOL readit,
952 BOOL debugout,
953 BOOL alloc,
954 TYPEDESC *tdesc,
955 DWORD *arg,
956 marshal_state *buf)
958 HRESULT hres = S_OK;
959 VARTYPE vartype;
961 TRACE("vt %s at %p\n",debugstr_vt(tdesc->vt),arg);
963 vartype = tdesc->vt;
964 if ((vartype & 0xf000) == VT_ARRAY)
965 vartype = VT_SAFEARRAY;
967 while (1) {
968 switch (vartype) {
969 case VT_VARIANT: {
970 if (readit)
972 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
973 unsigned char *buffer;
974 buffer = VARIANT_UserUnmarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
975 buf->curoff = buffer - buf->base;
977 return S_OK;
979 case VT_DATE:
980 case VT_I8:
981 case VT_UI8:
982 case VT_R8:
983 case VT_CY:
984 if (readit) {
985 hres = xbuf_get(buf,(LPBYTE)arg,8);
986 if (hres) ERR("Failed to read integer 8 byte\n");
988 if (debugout) TRACE_(olerelay)("%x%x",arg[0],arg[1]);
989 return hres;
990 case VT_ERROR:
991 case VT_I4:
992 case VT_INT:
993 case VT_UINT:
994 case VT_R4:
995 case VT_UI4:
996 if (readit) {
997 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
998 if (hres) ERR("Failed to read integer 4 byte\n");
1000 if (debugout) TRACE_(olerelay)("%x",*arg);
1001 return hres;
1002 case VT_I2:
1003 case VT_UI2:
1004 case VT_BOOL:
1005 if (readit) {
1006 DWORD x;
1007 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
1008 if (hres) ERR("Failed to read integer 4 byte\n");
1009 memcpy(arg,&x,2);
1011 if (debugout) TRACE_(olerelay)("%04x",*arg & 0xffff);
1012 return hres;
1013 case VT_I1:
1014 case VT_UI1:
1015 if (readit) {
1016 DWORD x;
1017 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
1018 if (hres) ERR("Failed to read integer 4 byte\n");
1019 memcpy(arg,&x,1);
1021 if (debugout) TRACE_(olerelay)("%02x",*arg & 0xff);
1022 return hres;
1023 case VT_BSTR: {
1024 if (readit)
1026 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1027 unsigned char *buffer;
1028 buffer = BSTR_UserUnmarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
1029 buf->curoff = buffer - buf->base;
1030 if (debugout) TRACE_(olerelay)("%s",debugstr_w(*(BSTR *)arg));
1032 return S_OK;
1034 case VT_PTR: {
1035 DWORD cookie;
1036 BOOL derefhere = TRUE;
1038 if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
1039 ITypeInfo *tinfo2;
1040 TYPEATTR *tattr;
1042 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
1043 if (hres) {
1044 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1045 return hres;
1047 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1048 switch (tattr->typekind) {
1049 case TKIND_ALIAS:
1050 if (tattr->tdescAlias.vt == VT_USERDEFINED)
1052 DWORD href = tattr->tdescAlias.u.hreftype;
1053 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
1054 ITypeInfo_Release(tinfo2);
1055 hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
1056 if (hres) {
1057 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1058 return hres;
1060 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1061 derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
1063 break;
1064 case TKIND_ENUM: /* confirmed */
1065 case TKIND_RECORD: /* FIXME: mostly untested */
1066 break;
1067 case TKIND_DISPATCH: /* will be done in VT_USERDEFINED case */
1068 case TKIND_INTERFACE: /* will be done in VT_USERDEFINED case */
1069 derefhere=FALSE;
1070 break;
1071 default:
1072 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
1073 derefhere=FALSE;
1074 break;
1076 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1077 ITypeInfo_Release(tinfo2);
1079 /* read it in all cases, we need to know if we have
1080 * NULL pointer or not.
1082 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1083 if (hres) {
1084 ERR("Failed to load pointer cookie.\n");
1085 return hres;
1087 if (cookie != 0x42424242) {
1088 /* we read a NULL ptr from the remote side */
1089 if (debugout) TRACE_(olerelay)("NULL");
1090 *arg = 0;
1091 return S_OK;
1093 if (debugout) TRACE_(olerelay)("*");
1094 if (alloc) {
1095 /* Allocate space for the referenced struct */
1096 if (derefhere)
1097 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo));
1099 if (derefhere)
1100 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
1101 else
1102 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
1104 case VT_UNKNOWN:
1105 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
1106 if (alloc)
1107 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
1108 hres = S_OK;
1109 if (readit)
1110 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
1111 if (debugout)
1112 TRACE_(olerelay)("unk(%p)",arg);
1113 return hres;
1114 case VT_DISPATCH:
1115 hres = S_OK;
1116 if (readit)
1117 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
1118 if (debugout)
1119 TRACE_(olerelay)("idisp(%p)",arg);
1120 return hres;
1121 case VT_VOID:
1122 if (debugout) TRACE_(olerelay)("<void>");
1123 return S_OK;
1124 case VT_USERDEFINED: {
1125 ITypeInfo *tinfo2;
1126 TYPEATTR *tattr;
1128 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1129 if (hres) {
1130 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
1131 return hres;
1133 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1134 if (hres) {
1135 ERR("Could not get typeattr in VT_USERDEFINED.\n");
1136 } else {
1137 switch (tattr->typekind) {
1138 case TKIND_DISPATCH:
1139 case TKIND_INTERFACE:
1140 if (readit)
1141 hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
1142 break;
1143 case TKIND_RECORD: {
1144 int i;
1146 if (debugout) TRACE_(olerelay)("{");
1147 for (i=0;i<tattr->cVars;i++) {
1148 VARDESC *vdesc;
1150 hres = ITypeInfo_GetVarDesc(tinfo2, i, &vdesc);
1151 if (hres) {
1152 ERR("Could not get vardesc of %d\n",i);
1153 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1154 ITypeInfo_Release(tinfo2);
1155 return hres;
1157 hres = deserialize_param(
1158 tinfo2,
1159 readit,
1160 debugout,
1161 alloc,
1162 &vdesc->elemdescVar.tdesc,
1163 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
1166 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
1167 if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1169 if (debugout) TRACE_(olerelay)("}");
1170 break;
1172 case TKIND_ALIAS:
1173 hres = deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
1174 break;
1175 case TKIND_ENUM:
1176 if (readit) {
1177 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1178 if (hres) ERR("Failed to read enum (4 byte)\n");
1180 if (debugout) TRACE_(olerelay)("%x",*arg);
1181 break;
1182 default:
1183 ERR("Unhandled typekind %d\n",tattr->typekind);
1184 hres = E_FAIL;
1185 break;
1187 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1189 if (hres)
1190 ERR("failed to stuballoc in TKIND_RECORD.\n");
1191 ITypeInfo_Release(tinfo2);
1192 return hres;
1194 case VT_CARRAY: {
1195 /* arg is pointing to the start of the array. */
1196 LPBYTE base = (LPBYTE) arg;
1197 ARRAYDESC *adesc = tdesc->u.lpadesc;
1198 int arrsize,i;
1199 arrsize = 1;
1200 if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1201 for (i=0;i<adesc->cDims;i++)
1202 arrsize *= adesc->rgbounds[i].cElements;
1203 if (_passbyref(&adesc->tdescElem, tinfo))
1205 base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo) * arrsize);
1206 *arg = (DWORD) base;
1208 for (i=0;i<arrsize;i++)
1209 deserialize_param(
1210 tinfo,
1211 readit,
1212 debugout,
1213 alloc,
1214 &adesc->tdescElem,
1215 (DWORD*)(base + i*_xsize(&adesc->tdescElem, tinfo)),
1218 return S_OK;
1220 case VT_SAFEARRAY: {
1221 if (readit)
1223 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1224 unsigned char *buffer;
1225 buffer = LPSAFEARRAY_UserUnmarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1226 buf->curoff = buffer - buf->base;
1228 return S_OK;
1230 default:
1231 ERR("No handler for VT type %d!\n",tdesc->vt);
1232 return S_OK;
1237 /* Retrieves a function's funcdesc, searching back into inherited interfaces. */
1238 static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, const FUNCDESC **fdesc,
1239 BSTR *iname, BSTR *fname, UINT *num)
1241 HRESULT hr;
1242 UINT i, impl_types;
1243 UINT inherited_funcs = 0;
1244 TYPEATTR *attr;
1246 if (fname) *fname = NULL;
1247 if (iname) *iname = NULL;
1248 if (num) *num = 0;
1249 *tactual = NULL;
1251 hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
1252 if (FAILED(hr))
1254 ERR("GetTypeAttr failed with %x\n",hr);
1255 return hr;
1258 if(attr->typekind == TKIND_DISPATCH)
1260 if(attr->wTypeFlags & TYPEFLAG_FDUAL)
1262 HREFTYPE href;
1263 ITypeInfo *tinfo2;
1265 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
1266 if(FAILED(hr))
1268 ERR("Cannot get interface href from dual dispinterface\n");
1269 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1270 return hr;
1272 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1273 if(FAILED(hr))
1275 ERR("Cannot get interface from dual dispinterface\n");
1276 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1277 return hr;
1279 hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
1280 ITypeInfo_Release(tinfo2);
1281 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1282 return hr;
1284 ERR("Shouldn't be called with a non-dual dispinterface\n");
1285 return E_FAIL;
1288 impl_types = attr->cImplTypes;
1289 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1291 for (i = 0; i < impl_types; i++)
1293 HREFTYPE href;
1294 ITypeInfo *pSubTypeInfo;
1295 UINT sub_funcs;
1297 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
1298 if (FAILED(hr)) return hr;
1299 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
1300 if (FAILED(hr)) return hr;
1302 hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
1303 inherited_funcs += sub_funcs;
1304 ITypeInfo_Release(pSubTypeInfo);
1305 if(SUCCEEDED(hr)) return hr;
1307 if(iMethod < inherited_funcs)
1309 ERR("shouldn't be here\n");
1310 return E_INVALIDARG;
1313 for(i = inherited_funcs; i <= iMethod; i++)
1315 hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
1316 if(FAILED(hr))
1318 if(num) *num = i;
1319 return hr;
1323 /* found it. We don't care about num so zero it */
1324 if(num) *num = 0;
1325 *tactual = tinfo;
1326 ITypeInfo_AddRef(*tactual);
1327 if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1328 if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1329 return S_OK;
1332 static inline BOOL is_in_elem(const ELEMDESC *elem)
1334 return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
1337 static inline BOOL is_out_elem(const ELEMDESC *elem)
1339 return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
1342 static DWORD WINAPI xCall(int method, void **args)
1344 TMProxyImpl *tpinfo = args[0];
1345 DWORD *xargs;
1346 const FUNCDESC *fdesc;
1347 HRESULT hres;
1348 int i;
1349 marshal_state buf;
1350 RPCOLEMESSAGE msg;
1351 ULONG status;
1352 BSTR fname,iname;
1353 BSTR names[10];
1354 UINT nrofnames;
1355 DWORD remoteresult = 0;
1356 ITypeInfo *tinfo;
1357 IRpcChannelBuffer *chanbuf;
1359 EnterCriticalSection(&tpinfo->crit);
1361 hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1362 if (hres) {
1363 ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1364 LeaveCriticalSection(&tpinfo->crit);
1365 return E_FAIL;
1368 if (!tpinfo->chanbuf)
1370 WARN("Tried to use disconnected proxy\n");
1371 ITypeInfo_Release(tinfo);
1372 LeaveCriticalSection(&tpinfo->crit);
1373 return RPC_E_DISCONNECTED;
1375 chanbuf = tpinfo->chanbuf;
1376 IRpcChannelBuffer_AddRef(chanbuf);
1378 LeaveCriticalSection(&tpinfo->crit);
1380 if (TRACE_ON(olerelay)) {
1381 TRACE_(olerelay)("->");
1382 if (iname)
1383 TRACE_(olerelay)("%s:",relaystr(iname));
1384 if (fname)
1385 TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1386 else
1387 TRACE_(olerelay)("%d",method);
1388 TRACE_(olerelay)("(");
1391 SysFreeString(iname);
1392 SysFreeString(fname);
1394 memset(&buf,0,sizeof(buf));
1396 /* normal typelib driven serializing */
1398 /* Need them for hack below */
1399 memset(names,0,sizeof(names));
1400 if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1401 nrofnames = 0;
1402 if (nrofnames > sizeof(names)/sizeof(names[0]))
1403 ERR("Need more names!\n");
1405 xargs = (DWORD *)(args + 1);
1406 for (i=0;i<fdesc->cParams;i++) {
1407 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1408 if (TRACE_ON(olerelay)) {
1409 if (i) TRACE_(olerelay)(",");
1410 if (i+1<nrofnames && names[i+1])
1411 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1413 /* No need to marshal other data than FIN and any VT_PTR. */
1414 if (!is_in_elem(elem))
1416 if (elem->tdesc.vt != VT_PTR)
1418 xargs+=_argsize(&elem->tdesc, tinfo);
1419 TRACE_(olerelay)("[out]");
1420 continue;
1422 else
1424 memset( *(void **)xargs, 0, _xsize( elem->tdesc.u.lptdesc, tinfo ) );
1428 hres = serialize_param(
1429 tinfo,
1430 is_in_elem(elem),
1431 TRACE_ON(olerelay),
1432 FALSE,
1433 &elem->tdesc,
1434 xargs,
1435 &buf
1438 if (hres) {
1439 ERR("Failed to serialize param, hres %x\n",hres);
1440 break;
1442 xargs+=_argsize(&elem->tdesc, tinfo);
1444 TRACE_(olerelay)(")");
1446 memset(&msg,0,sizeof(msg));
1447 msg.cbBuffer = buf.curoff;
1448 msg.iMethod = method;
1449 hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1450 if (hres) {
1451 ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1452 goto exit;
1454 memcpy(msg.Buffer,buf.base,buf.curoff);
1455 TRACE_(olerelay)("\n");
1456 hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1457 if (hres) {
1458 ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1459 goto exit;
1462 TRACE_(olerelay)(" status = %08x (",status);
1463 if (buf.base)
1464 buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1465 else
1466 buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1467 buf.size = msg.cbBuffer;
1468 memcpy(buf.base,msg.Buffer,buf.size);
1469 buf.curoff = 0;
1471 /* generic deserializer using typelib description */
1472 xargs = (DWORD *)(args + 1);
1473 status = S_OK;
1474 for (i=0;i<fdesc->cParams;i++) {
1475 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1477 if (i) TRACE_(olerelay)(",");
1478 if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1480 /* No need to marshal other data than FOUT and any VT_PTR */
1481 if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1482 xargs += _argsize(&elem->tdesc, tinfo);
1483 TRACE_(olerelay)("[in]");
1484 continue;
1486 hres = deserialize_param(
1487 tinfo,
1488 is_out_elem(elem),
1489 TRACE_ON(olerelay),
1490 FALSE,
1491 &(elem->tdesc),
1492 xargs,
1493 &buf
1495 if (hres) {
1496 ERR("Failed to unmarshall param, hres %x\n",hres);
1497 status = hres;
1498 break;
1500 xargs += _argsize(&elem->tdesc, tinfo);
1503 hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1504 if (hres != S_OK)
1505 goto exit;
1506 TRACE_(olerelay)(") = %08x\n", remoteresult);
1508 hres = remoteresult;
1510 exit:
1511 IRpcChannelBuffer_FreeBuffer(chanbuf,&msg);
1512 for (i = 0; i < nrofnames; i++)
1513 SysFreeString(names[i]);
1514 HeapFree(GetProcessHeap(),0,buf.base);
1515 IRpcChannelBuffer_Release(chanbuf);
1516 ITypeInfo_Release(tinfo);
1517 TRACE("-- 0x%08x\n", hres);
1518 return hres;
1521 static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1523 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1525 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1527 if (proxy->outerunknown)
1528 return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1530 FIXME("No interface\n");
1531 return E_NOINTERFACE;
1534 static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1536 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1538 TRACE("\n");
1540 if (proxy->outerunknown)
1541 return IUnknown_AddRef(proxy->outerunknown);
1543 return 2; /* FIXME */
1546 static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1548 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1550 TRACE("\n");
1552 if (proxy->outerunknown)
1553 return IUnknown_Release(proxy->outerunknown);
1555 return 1; /* FIXME */
1558 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1560 TMProxyImpl *This = (TMProxyImpl *)iface;
1562 TRACE("(%p)\n", pctinfo);
1564 return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1567 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1569 TMProxyImpl *This = (TMProxyImpl *)iface;
1571 TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1573 return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1576 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1578 TMProxyImpl *This = (TMProxyImpl *)iface;
1580 TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1582 return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1583 cNames, lcid, rgDispId);
1586 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1587 WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1588 EXCEPINFO * pExcepInfo, UINT * puArgErr)
1590 TMProxyImpl *This = (TMProxyImpl *)iface;
1592 TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1593 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
1594 pExcepInfo, puArgErr);
1596 return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1597 wFlags, pDispParams, pVarResult, pExcepInfo,
1598 puArgErr);
1601 typedef struct
1603 IRpcChannelBuffer IRpcChannelBuffer_iface;
1604 LONG refs;
1605 /* the IDispatch-derived interface we are handling */
1606 IID tmarshal_iid;
1607 IRpcChannelBuffer *pDelegateChannel;
1608 } TMarshalDispatchChannel;
1610 static inline TMarshalDispatchChannel *impl_from_IRpcChannelBuffer(IRpcChannelBuffer *iface)
1612 return CONTAINING_RECORD(iface, TMarshalDispatchChannel, IRpcChannelBuffer_iface);
1615 static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(IRpcChannelBuffer *iface, REFIID riid, LPVOID *ppv)
1617 *ppv = NULL;
1618 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
1620 *ppv = iface;
1621 IRpcChannelBuffer_AddRef(iface);
1622 return S_OK;
1624 return E_NOINTERFACE;
1627 static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
1629 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1630 return InterlockedIncrement(&This->refs);
1633 static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
1635 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1636 ULONG ref;
1638 ref = InterlockedDecrement(&This->refs);
1639 if (ref)
1640 return ref;
1642 IRpcChannelBuffer_Release(This->pDelegateChannel);
1643 HeapFree(GetProcessHeap(), 0, This);
1644 return 0;
1647 static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1649 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1650 TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
1651 /* Note: we are pretending to invoke a method on the interface identified
1652 * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
1653 * without the RPC runtime getting confused by not exporting an IDispatch interface */
1654 return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
1657 static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1659 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1660 TRACE("(%p, %p)\n", olemsg, pstatus);
1661 return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
1664 static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1666 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1667 TRACE("(%p)\n", olemsg);
1668 return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
1671 static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1673 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1674 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1675 return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
1678 static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
1680 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1681 TRACE("()\n");
1682 return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
1685 static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
1687 TMarshalDispatchChannel_QueryInterface,
1688 TMarshalDispatchChannel_AddRef,
1689 TMarshalDispatchChannel_Release,
1690 TMarshalDispatchChannel_GetBuffer,
1691 TMarshalDispatchChannel_SendReceive,
1692 TMarshalDispatchChannel_FreeBuffer,
1693 TMarshalDispatchChannel_GetDestCtx,
1694 TMarshalDispatchChannel_IsConnected
1697 static HRESULT TMarshalDispatchChannel_Create(
1698 IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
1699 IRpcChannelBuffer **ppChannel)
1701 TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1702 if (!This)
1703 return E_OUTOFMEMORY;
1705 This->IRpcChannelBuffer_iface.lpVtbl = &TMarshalDispatchChannelVtbl;
1706 This->refs = 1;
1707 IRpcChannelBuffer_AddRef(pDelegateChannel);
1708 This->pDelegateChannel = pDelegateChannel;
1709 This->tmarshal_iid = *tmarshal_riid;
1711 *ppChannel = &This->IRpcChannelBuffer_iface;
1712 return S_OK;
1716 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
1718 HRESULT hr;
1719 CLSID clsid;
1721 if ((hr = CoGetPSClsid(riid, &clsid)))
1722 return hr;
1723 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
1724 &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1727 static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
1729 int j;
1730 /* nrofargs including This */
1731 int nrofargs = 1;
1732 ITypeInfo *tinfo2;
1733 TMAsmProxy *xasm = proxy->asmstubs + num;
1734 HRESULT hres;
1735 const FUNCDESC *fdesc;
1737 hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
1738 if (hres) {
1739 ERR("GetFuncDesc %x should not fail here.\n",hres);
1740 return hres;
1742 ITypeInfo_Release(tinfo2);
1743 /* some args take more than 4 byte on the stack */
1744 for (j=0;j<fdesc->cParams;j++)
1745 nrofargs += _argsize(&fdesc->lprgelemdescParam[j].tdesc, proxy->tinfo);
1747 #ifdef __i386__
1748 if (fdesc->callconv != CC_STDCALL) {
1749 ERR("calling convention is not stdcall????\n");
1750 return E_FAIL;
1752 /* leal 4(%esp),%eax
1753 * pushl %eax
1754 * pushl <nr>
1755 * call xCall
1756 * lret <nr>
1758 xasm->lealeax = 0x0424448d;
1759 xasm->pushleax = 0x50;
1760 xasm->pushlval = 0x68;
1761 xasm->nr = num;
1762 xasm->lcall = 0xe8;
1763 xasm->xcall = (char *)xCall - (char *)&xasm->lret;
1764 xasm->lret = 0xc2;
1765 xasm->bytestopop = nrofargs * 4;
1766 xasm->nop = 0x9090;
1767 proxy->lpvtbl[fdesc->oVft / sizeof(void *)] = xasm;
1768 #else
1769 FIXME("not implemented on non i386\n");
1770 return E_FAIL;
1771 #endif
1772 return S_OK;
1775 static HRESULT WINAPI
1776 PSFacBuf_CreateProxy(
1777 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1778 IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1780 HRESULT hres;
1781 ITypeInfo *tinfo;
1782 unsigned int i, nroffuncs, vtbl_size;
1783 TMProxyImpl *proxy;
1784 TYPEATTR *typeattr;
1785 BOOL defer_to_dispatch = FALSE;
1787 TRACE("(...%s...)\n",debugstr_guid(riid));
1788 hres = _get_typeinfo_for_iid(riid,&tinfo);
1789 if (hres) {
1790 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1791 return hres;
1794 hres = num_of_funcs(tinfo, &nroffuncs, &vtbl_size);
1795 TRACE("Got %d funcs, vtbl size %d\n", nroffuncs, vtbl_size);
1797 if (FAILED(hres)) {
1798 ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
1799 ITypeInfo_Release(tinfo);
1800 return hres;
1803 proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1804 if (!proxy) return E_OUTOFMEMORY;
1806 proxy->dispatch = NULL;
1807 proxy->dispatch_proxy = NULL;
1808 proxy->outerunknown = pUnkOuter;
1809 proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1810 if (!proxy->asmstubs) {
1811 ERR("Could not commit pages for proxy thunks\n");
1812 CoTaskMemFree(proxy);
1813 return E_OUTOFMEMORY;
1815 proxy->IRpcProxyBuffer_iface.lpVtbl = &tmproxyvtable;
1816 /* one reference for the proxy */
1817 proxy->ref = 1;
1818 proxy->tinfo = tinfo;
1819 proxy->iid = *riid;
1820 proxy->chanbuf = 0;
1822 InitializeCriticalSection(&proxy->crit);
1823 proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
1825 proxy->lpvtbl = HeapAlloc(GetProcessHeap(), 0, vtbl_size);
1827 /* if we derive from IDispatch then defer to its proxy for its methods */
1828 hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
1829 if (hres == S_OK)
1831 if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
1833 IPSFactoryBuffer *factory_buffer;
1834 hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1835 if (hres == S_OK)
1837 hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
1838 &IID_IDispatch, &proxy->dispatch_proxy,
1839 (void **)&proxy->dispatch);
1840 IPSFactoryBuffer_Release(factory_buffer);
1842 if ((hres == S_OK) && (nroffuncs < 7))
1844 ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
1845 hres = E_UNEXPECTED;
1847 if (hres == S_OK)
1849 defer_to_dispatch = TRUE;
1852 ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
1855 for (i=0;i<nroffuncs;i++) {
1856 switch (i) {
1857 case 0:
1858 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
1859 break;
1860 case 1:
1861 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
1862 break;
1863 case 2:
1864 proxy->lpvtbl[i] = ProxyIUnknown_Release;
1865 break;
1866 case 3:
1867 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1868 else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
1869 break;
1870 case 4:
1871 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1872 else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
1873 break;
1874 case 5:
1875 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1876 else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
1877 break;
1878 case 6:
1879 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1880 else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
1881 break;
1882 default:
1883 hres = init_proxy_entry_point(proxy, i);
1887 if (hres == S_OK)
1889 *ppv = proxy;
1890 *ppProxy = &proxy->IRpcProxyBuffer_iface;
1891 IUnknown_AddRef((IUnknown *)*ppv);
1892 return S_OK;
1894 else
1895 TMProxyImpl_Release(&proxy->IRpcProxyBuffer_iface);
1896 return hres;
1899 typedef struct _TMStubImpl {
1900 IRpcStubBuffer IRpcStubBuffer_iface;
1901 LONG ref;
1903 LPUNKNOWN pUnk;
1904 ITypeInfo *tinfo;
1905 IID iid;
1906 IRpcStubBuffer *dispatch_stub;
1907 BOOL dispatch_derivative;
1908 } TMStubImpl;
1910 static inline TMStubImpl *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
1912 return CONTAINING_RECORD(iface, TMStubImpl, IRpcStubBuffer_iface);
1915 static HRESULT WINAPI
1916 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1918 if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1919 *ppv = iface;
1920 IRpcStubBuffer_AddRef(iface);
1921 return S_OK;
1923 FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1924 return E_NOINTERFACE;
1927 static ULONG WINAPI
1928 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1930 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1931 ULONG refCount = InterlockedIncrement(&This->ref);
1933 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
1935 return refCount;
1938 static ULONG WINAPI
1939 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1941 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1942 ULONG refCount = InterlockedDecrement(&This->ref);
1944 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
1946 if (!refCount)
1948 IRpcStubBuffer_Disconnect(iface);
1949 ITypeInfo_Release(This->tinfo);
1950 if (This->dispatch_stub)
1951 IRpcStubBuffer_Release(This->dispatch_stub);
1952 CoTaskMemFree(This);
1954 return refCount;
1957 static HRESULT WINAPI
1958 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1960 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1962 TRACE("(%p)->(%p)\n", This, pUnkServer);
1964 IUnknown_AddRef(pUnkServer);
1965 This->pUnk = pUnkServer;
1967 if (This->dispatch_stub)
1968 IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);
1970 return S_OK;
1973 static void WINAPI
1974 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1976 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1978 TRACE("(%p)->()\n", This);
1980 if (This->pUnk)
1982 IUnknown_Release(This->pUnk);
1983 This->pUnk = NULL;
1986 if (This->dispatch_stub)
1987 IRpcStubBuffer_Disconnect(This->dispatch_stub);
1990 static HRESULT WINAPI
1991 TMStubImpl_Invoke(
1992 LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1994 #ifdef __i386__
1995 int i;
1996 const FUNCDESC *fdesc;
1997 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
1998 HRESULT hres;
1999 DWORD *args = NULL, res, *xargs, nrofargs;
2000 marshal_state buf;
2001 UINT nrofnames = 0;
2002 BSTR names[10];
2003 BSTR iname = NULL;
2004 ITypeInfo *tinfo = NULL;
2006 TRACE("...\n");
2008 if (xmsg->iMethod < 3) {
2009 ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
2010 return E_UNEXPECTED;
2013 if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
2015 if (!This->dispatch_stub)
2017 IPSFactoryBuffer *factory_buffer;
2018 hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
2019 if (hres == S_OK)
2021 hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
2022 This->pUnk, &This->dispatch_stub);
2023 IPSFactoryBuffer_Release(factory_buffer);
2025 if (hres != S_OK)
2026 return hres;
2028 return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
2031 memset(&buf,0,sizeof(buf));
2032 buf.size = xmsg->cbBuffer;
2033 buf.base = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
2034 memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
2035 buf.curoff = 0;
2037 hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
2038 if (hres) {
2039 ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
2040 return hres;
2043 if (iname && !lstrcmpW(iname, IDispatchW))
2045 ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
2046 hres = E_UNEXPECTED;
2047 SysFreeString (iname);
2048 goto exit;
2051 SysFreeString (iname);
2053 /* Need them for hack below */
2054 memset(names,0,sizeof(names));
2055 ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
2056 if (nrofnames > sizeof(names)/sizeof(names[0])) {
2057 ERR("Need more names!\n");
2060 /*dump_FUNCDESC(fdesc);*/
2061 nrofargs = 0;
2062 for (i=0;i<fdesc->cParams;i++)
2063 nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo);
2064 args = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(nrofargs+1)*sizeof(DWORD));
2065 if (!args)
2067 hres = E_OUTOFMEMORY;
2068 goto exit;
2071 /* Allocate all stuff used by call. */
2072 xargs = args+1;
2073 for (i=0;i<fdesc->cParams;i++) {
2074 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
2076 hres = deserialize_param(
2077 tinfo,
2078 is_in_elem(elem),
2079 FALSE,
2080 TRUE,
2081 &(elem->tdesc),
2082 xargs,
2083 &buf
2085 xargs += _argsize(&elem->tdesc, tinfo);
2086 if (hres) {
2087 ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2088 break;
2092 args[0] = (DWORD)This->pUnk;
2094 __TRY
2096 res = _invoke(
2097 (*((FARPROC**)args[0]))[fdesc->oVft/4],
2098 fdesc->callconv,
2099 (xargs-args),
2100 args
2103 __EXCEPT_ALL
2105 DWORD dwExceptionCode = GetExceptionCode();
2106 ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2107 if (FAILED(dwExceptionCode))
2108 hres = dwExceptionCode;
2109 else
2110 hres = HRESULT_FROM_WIN32(dwExceptionCode);
2112 __ENDTRY
2114 if (hres != S_OK)
2115 goto exit;
2117 buf.curoff = 0;
2119 xargs = args+1;
2120 for (i=0;i<fdesc->cParams;i++) {
2121 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
2122 hres = serialize_param(
2123 tinfo,
2124 is_out_elem(elem),
2125 FALSE,
2126 TRUE,
2127 &elem->tdesc,
2128 xargs,
2129 &buf
2131 xargs += _argsize(&elem->tdesc, tinfo);
2132 if (hres) {
2133 ERR("Failed to stuballoc param, hres %x\n",hres);
2134 break;
2138 hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2140 if (hres != S_OK)
2141 goto exit;
2143 xmsg->cbBuffer = buf.curoff;
2144 hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
2145 if (hres != S_OK)
2146 ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2148 if (hres == S_OK)
2149 memcpy(xmsg->Buffer, buf.base, buf.curoff);
2151 exit:
2152 for (i = 0; i < nrofnames; i++)
2153 SysFreeString(names[i]);
2155 ITypeInfo_Release(tinfo);
2156 HeapFree(GetProcessHeap(), 0, args);
2158 HeapFree(GetProcessHeap(), 0, buf.base);
2160 TRACE("returning\n");
2161 return hres;
2162 #else
2163 FIXME( "not implemented on non-i386\n" );
2164 return E_FAIL;
2165 #endif
2168 static LPRPCSTUBBUFFER WINAPI
2169 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
2170 FIXME("Huh (%s)?\n",debugstr_guid(riid));
2171 return NULL;
2174 static ULONG WINAPI
2175 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
2176 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2178 FIXME("()\n");
2179 return This->ref; /*FIXME? */
2182 static HRESULT WINAPI
2183 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
2184 return E_NOTIMPL;
2187 static void WINAPI
2188 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
2189 return;
2192 static const IRpcStubBufferVtbl tmstubvtbl = {
2193 TMStubImpl_QueryInterface,
2194 TMStubImpl_AddRef,
2195 TMStubImpl_Release,
2196 TMStubImpl_Connect,
2197 TMStubImpl_Disconnect,
2198 TMStubImpl_Invoke,
2199 TMStubImpl_IsIIDSupported,
2200 TMStubImpl_CountRefs,
2201 TMStubImpl_DebugServerQueryInterface,
2202 TMStubImpl_DebugServerRelease
2205 static HRESULT WINAPI
2206 PSFacBuf_CreateStub(
2207 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
2208 IRpcStubBuffer** ppStub
2210 HRESULT hres;
2211 ITypeInfo *tinfo;
2212 TMStubImpl *stub;
2213 TYPEATTR *typeattr;
2215 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2217 hres = _get_typeinfo_for_iid(riid,&tinfo);
2218 if (hres) {
2219 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2220 return hres;
2223 stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2224 if (!stub)
2225 return E_OUTOFMEMORY;
2226 stub->IRpcStubBuffer_iface.lpVtbl = &tmstubvtbl;
2227 stub->ref = 1;
2228 stub->tinfo = tinfo;
2229 stub->dispatch_stub = NULL;
2230 stub->dispatch_derivative = FALSE;
2231 stub->iid = *riid;
2232 hres = IRpcStubBuffer_Connect(&stub->IRpcStubBuffer_iface,pUnkServer);
2233 *ppStub = &stub->IRpcStubBuffer_iface;
2234 TRACE("IRpcStubBuffer: %p\n", stub);
2235 if (hres)
2236 ERR("Connect to pUnkServer failed?\n");
2238 /* if we derive from IDispatch then defer to its stub for some of its methods */
2239 hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2240 if (hres == S_OK)
2242 if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2243 stub->dispatch_derivative = TRUE;
2244 ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2247 return hres;
2250 static const IPSFactoryBufferVtbl psfacbufvtbl = {
2251 PSFacBuf_QueryInterface,
2252 PSFacBuf_AddRef,
2253 PSFacBuf_Release,
2254 PSFacBuf_CreateProxy,
2255 PSFacBuf_CreateStub
2258 /* This is the whole PSFactoryBuffer object, just the vtableptr */
2259 static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
2261 /***********************************************************************
2262 * TMARSHAL_DllGetClassObject
2264 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
2266 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
2267 *ppv = &lppsfac;
2268 return S_OK;
2270 return E_NOINTERFACE;