rsaenh: Avoid double 'va_end(args)' in case of a premature loop termination.
[wine.git] / dlls / oleaut32 / tmarshal.c
blob5fd1fdd6338fae48f8b338b295dc9a5ed7295074
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 newsize = max(newsize, buf->size * 2);
83 buf->base = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf->base, newsize);
84 if(!buf->base)
85 return E_OUTOFMEMORY;
87 else
89 newsize = max(newsize, 256);
90 buf->base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
91 if(!buf->base)
92 return E_OUTOFMEMORY;
94 buf->size = newsize;
95 return S_OK;
98 static HRESULT
99 xbuf_add(marshal_state *buf, const BYTE *stuff, DWORD size)
101 HRESULT hr;
103 if(buf->size - buf->curoff < size)
105 hr = xbuf_resize(buf, buf->size + size);
106 if(FAILED(hr)) return hr;
108 memcpy(buf->base+buf->curoff,stuff,size);
109 buf->curoff += size;
110 return S_OK;
113 static HRESULT
114 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
115 if (buf->size < buf->curoff+size) return E_FAIL;
116 memcpy(stuff,buf->base+buf->curoff,size);
117 buf->curoff += size;
118 return S_OK;
121 static HRESULT
122 xbuf_skip(marshal_state *buf, DWORD size) {
123 if (buf->size < buf->curoff+size) return E_FAIL;
124 buf->curoff += size;
125 return S_OK;
128 static HRESULT
129 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
130 IStream *pStm;
131 ULARGE_INTEGER newpos;
132 LARGE_INTEGER seekto;
133 ULONG res;
134 HRESULT hres;
135 DWORD xsize;
137 TRACE("...%s...\n",debugstr_guid(riid));
139 *pUnk = NULL;
140 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
141 if (hres) {
142 ERR("xbuf_get failed\n");
143 return hres;
146 if (xsize == 0) return S_OK;
148 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
149 if (hres) {
150 ERR("Stream create failed %x\n",hres);
151 return hres;
154 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
155 if (hres) {
156 ERR("stream write %x\n",hres);
157 IStream_Release(pStm);
158 return hres;
161 memset(&seekto,0,sizeof(seekto));
162 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
163 if (hres) {
164 ERR("Failed Seek %x\n",hres);
165 IStream_Release(pStm);
166 return hres;
169 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
170 if (hres) {
171 ERR("Unmarshalling interface %s failed with %x\n",debugstr_guid(riid),hres);
172 IStream_Release(pStm);
173 return hres;
176 IStream_Release(pStm);
177 return xbuf_skip(buf,xsize);
180 static HRESULT
181 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
182 LPBYTE tempbuf = NULL;
183 IStream *pStm = NULL;
184 STATSTG ststg;
185 ULARGE_INTEGER newpos;
186 LARGE_INTEGER seekto;
187 ULONG res;
188 DWORD xsize;
189 HRESULT hres;
191 if (!pUnk) {
192 /* this is valid, if for instance we serialize
193 * a VT_DISPATCH with NULL ptr which apparently
194 * can happen. S_OK to make sure we continue
195 * serializing.
197 WARN("pUnk is NULL\n");
198 xsize = 0;
199 return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
202 TRACE("...%s...\n",debugstr_guid(riid));
204 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
205 if (hres) {
206 ERR("Stream create failed %x\n",hres);
207 goto fail;
210 hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
211 if (hres) {
212 ERR("Marshalling interface %s failed with %x\n", debugstr_guid(riid), hres);
213 goto fail;
216 hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
217 if (hres) {
218 ERR("Stream stat failed\n");
219 goto fail;
222 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
223 memset(&seekto,0,sizeof(seekto));
224 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
225 if (hres) {
226 ERR("Failed Seek %x\n",hres);
227 goto fail;
230 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
231 if (hres) {
232 ERR("Failed Read %x\n",hres);
233 goto fail;
236 xsize = ststg.cbSize.u.LowPart;
237 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
238 hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
240 HeapFree(GetProcessHeap(),0,tempbuf);
241 IStream_Release(pStm);
243 return hres;
245 fail:
246 xsize = 0;
247 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
248 if (pStm) IStream_Release(pStm);
249 HeapFree(GetProcessHeap(), 0, tempbuf);
250 return hres;
253 /********************* OLE Proxy/Stub Factory ********************************/
254 static HRESULT WINAPI
255 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
256 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
257 *ppv = iface;
258 /* No ref counting, static class */
259 return S_OK;
261 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
262 return E_NOINTERFACE;
265 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
266 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
268 struct ifacepsredirect_data
270 ULONG size;
271 DWORD mask;
272 GUID iid;
273 ULONG nummethods;
274 GUID tlbid;
275 GUID base;
276 ULONG name_len;
277 ULONG name_offset;
280 struct tlibredirect_data
282 ULONG size;
283 DWORD res;
284 ULONG name_len;
285 ULONG name_offset;
286 LANGID langid;
287 WORD flags;
288 ULONG help_len;
289 ULONG help_offset;
290 WORD major_version;
291 WORD minor_version;
294 static BOOL actctx_get_typelib_module(REFIID riid, WCHAR *module, DWORD len)
296 struct ifacepsredirect_data *iface;
297 struct tlibredirect_data *tlib;
298 ACTCTX_SECTION_KEYED_DATA data;
299 WCHAR *ptrW;
301 data.cbSize = sizeof(data);
302 if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
303 riid, &data))
304 return FALSE;
306 iface = (struct ifacepsredirect_data*)data.lpData;
307 if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION,
308 &iface->tlbid, &data))
309 return FALSE;
311 tlib = (struct tlibredirect_data*)data.lpData;
312 ptrW = (WCHAR*)((BYTE*)data.lpSectionBase + tlib->name_offset);
314 if (tlib->name_len/sizeof(WCHAR) >= len) {
315 ERR("need larger module buffer, %u\n", tlib->name_len);
316 return FALSE;
319 memcpy(module, ptrW, tlib->name_len);
320 module[tlib->name_len/sizeof(WCHAR)] = 0;
321 return TRUE;
324 static HRESULT reg_get_typelib_module(REFIID riid, WCHAR *module, DWORD len)
326 HKEY ikey;
327 REGSAM opposite = (sizeof(void*) == 8) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
328 BOOL is_wow64;
329 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
330 char tlfn[260];
331 DWORD tlguidlen, verlen, type;
332 LONG tlfnlen, err;
334 sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
335 riid->Data1, riid->Data2, riid->Data3,
336 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
337 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
340 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ,&ikey);
341 if (err && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64)
342 && is_wow64))) {
343 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ|opposite,&ikey);
345 if (err) {
346 ERR("No %s key found.\n",interfacekey);
347 return E_FAIL;
349 tlguidlen = sizeof(tlguid);
350 if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
351 ERR("Getting typelib guid failed.\n");
352 RegCloseKey(ikey);
353 return E_FAIL;
355 verlen = sizeof(ver);
356 if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
357 ERR("Could not get version value?\n");
358 RegCloseKey(ikey);
359 return E_FAIL;
361 RegCloseKey(ikey);
362 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win%u",tlguid,ver,(sizeof(void*) == 8) ? 64 : 32);
363 tlfnlen = sizeof(tlfn);
364 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
365 #ifdef _WIN64
366 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
367 tlfnlen = sizeof(tlfn);
368 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
369 #endif
370 ERR("Could not get typelib fn?\n");
371 return E_FAIL;
372 #ifdef _WIN64
374 #endif
376 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, module, len);
377 return S_OK;
380 static HRESULT
381 _get_typeinfo_for_iid(REFIID riid, ITypeInfo **typeinfo)
383 OLECHAR moduleW[260];
384 ITypeLib *typelib;
385 HRESULT hres;
387 *typeinfo = NULL;
389 moduleW[0] = 0;
390 if (!actctx_get_typelib_module(riid, moduleW, sizeof(moduleW)/sizeof(moduleW[0]))) {
391 hres = reg_get_typelib_module(riid, moduleW, sizeof(moduleW)/sizeof(moduleW[0]));
392 if (FAILED(hres))
393 return hres;
396 hres = LoadTypeLib(moduleW, &typelib);
397 if (hres != S_OK) {
398 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
399 return hres;
402 hres = ITypeLib_GetTypeInfoOfGuid(typelib, riid, typeinfo);
403 ITypeLib_Release(typelib);
404 if (hres != S_OK)
405 ERR("typelib does not contain info for %s\n", debugstr_guid(riid));
407 return hres;
411 * Determine the number of functions including all inherited functions
412 * and well as the size of the vtbl.
413 * Note for non-dual dispinterfaces we simply return the size of IDispatch.
415 static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num,
416 unsigned int *vtbl_size)
418 HRESULT hr;
419 TYPEATTR *attr;
420 ITypeInfo *tinfo2;
421 UINT inherited_funcs = 0, i;
423 *num = 0;
424 if(vtbl_size) *vtbl_size = 0;
426 hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
427 if (hr)
429 ERR("GetTypeAttr failed with %x\n", hr);
430 return hr;
433 if(attr->typekind == TKIND_DISPATCH)
435 if(attr->wTypeFlags & TYPEFLAG_FDUAL)
437 HREFTYPE href;
439 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
440 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
441 if(FAILED(hr))
443 ERR("Unable to get interface href from dual dispinterface\n");
444 return hr;
446 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
447 if(FAILED(hr))
449 ERR("Unable to get interface from dual dispinterface\n");
450 return hr;
452 hr = num_of_funcs(tinfo2, num, vtbl_size);
453 ITypeInfo_Release(tinfo2);
454 return hr;
456 else /* non-dual dispinterface */
458 /* These will be the size of IDispatchVtbl */
459 *num = attr->cbSizeVft / sizeof(void *);
460 if(vtbl_size) *vtbl_size = attr->cbSizeVft;
461 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
462 return hr;
466 for (i = 0; i < attr->cImplTypes; i++)
468 HREFTYPE href;
469 ITypeInfo *pSubTypeInfo;
470 UINT sub_funcs;
472 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
473 if (FAILED(hr)) goto end;
474 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
475 if (FAILED(hr)) goto end;
477 hr = num_of_funcs(pSubTypeInfo, &sub_funcs, NULL);
478 ITypeInfo_Release(pSubTypeInfo);
480 if(FAILED(hr)) goto end;
481 inherited_funcs += sub_funcs;
484 *num = inherited_funcs + attr->cFuncs;
485 if(vtbl_size) *vtbl_size = attr->cbSizeVft;
487 end:
488 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
489 return hr;
492 #ifdef __i386__
494 #include "pshpack1.h"
496 typedef struct _TMAsmProxy {
497 DWORD lealeax;
498 BYTE pushleax;
499 BYTE pushlval;
500 DWORD nr;
501 BYTE lcall;
502 DWORD xcall;
503 BYTE lret;
504 WORD bytestopop;
505 WORD nop;
506 } TMAsmProxy;
508 #include "poppack.h"
510 #else /* __i386__ */
511 # warning You need to implement stubless proxies for your architecture
512 typedef struct _TMAsmProxy {
513 } TMAsmProxy;
514 #endif
516 typedef struct _TMProxyImpl {
517 LPVOID *lpvtbl;
518 IRpcProxyBuffer IRpcProxyBuffer_iface;
519 LONG ref;
521 TMAsmProxy *asmstubs;
522 ITypeInfo* tinfo;
523 IRpcChannelBuffer* chanbuf;
524 IID iid;
525 CRITICAL_SECTION crit;
526 IUnknown *outerunknown;
527 IDispatch *dispatch;
528 IRpcProxyBuffer *dispatch_proxy;
529 } TMProxyImpl;
531 static inline TMProxyImpl *impl_from_IRpcProxyBuffer( IRpcProxyBuffer *iface )
533 return CONTAINING_RECORD(iface, TMProxyImpl, IRpcProxyBuffer_iface);
536 static HRESULT WINAPI
537 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
539 TRACE("()\n");
540 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
541 *ppv = iface;
542 IRpcProxyBuffer_AddRef(iface);
543 return S_OK;
545 FIXME("no interface for %s\n",debugstr_guid(riid));
546 return E_NOINTERFACE;
549 static ULONG WINAPI
550 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
552 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
553 ULONG refCount = InterlockedIncrement(&This->ref);
555 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
557 return refCount;
560 static ULONG WINAPI
561 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
563 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
564 ULONG refCount = InterlockedDecrement(&This->ref);
566 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
568 if (!refCount)
570 if (This->dispatch_proxy) IRpcProxyBuffer_Release(This->dispatch_proxy);
571 This->crit.DebugInfo->Spare[0] = 0;
572 DeleteCriticalSection(&This->crit);
573 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
574 VirtualFree(This->asmstubs, 0, MEM_RELEASE);
575 HeapFree(GetProcessHeap(), 0, This->lpvtbl);
576 ITypeInfo_Release(This->tinfo);
577 CoTaskMemFree(This);
579 return refCount;
582 static HRESULT WINAPI
583 TMProxyImpl_Connect(
584 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
586 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
588 TRACE("(%p)\n", pRpcChannelBuffer);
590 EnterCriticalSection(&This->crit);
592 IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
593 This->chanbuf = pRpcChannelBuffer;
595 LeaveCriticalSection(&This->crit);
597 if (This->dispatch_proxy)
599 IRpcChannelBuffer *pDelegateChannel;
600 HRESULT hr = TMarshalDispatchChannel_Create(pRpcChannelBuffer, &This->iid, &pDelegateChannel);
601 if (FAILED(hr))
602 return hr;
603 hr = IRpcProxyBuffer_Connect(This->dispatch_proxy, pDelegateChannel);
604 IRpcChannelBuffer_Release(pDelegateChannel);
605 return hr;
608 return S_OK;
611 static void WINAPI
612 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
614 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
616 TRACE("()\n");
618 EnterCriticalSection(&This->crit);
620 IRpcChannelBuffer_Release(This->chanbuf);
621 This->chanbuf = NULL;
623 LeaveCriticalSection(&This->crit);
625 if (This->dispatch_proxy)
626 IRpcProxyBuffer_Disconnect(This->dispatch_proxy);
630 static const IRpcProxyBufferVtbl tmproxyvtable = {
631 TMProxyImpl_QueryInterface,
632 TMProxyImpl_AddRef,
633 TMProxyImpl_Release,
634 TMProxyImpl_Connect,
635 TMProxyImpl_Disconnect
638 /* how much space do we use on stack in DWORD steps. */
639 static int
640 _argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
641 switch (tdesc->vt) {
642 case VT_I8:
643 case VT_UI8:
644 return 8/sizeof(DWORD);
645 case VT_R8:
646 return sizeof(double)/sizeof(DWORD);
647 case VT_CY:
648 return sizeof(CY)/sizeof(DWORD);
649 case VT_DATE:
650 return sizeof(DATE)/sizeof(DWORD);
651 case VT_DECIMAL:
652 return (sizeof(DECIMAL)+3)/sizeof(DWORD);
653 case VT_VARIANT:
654 return (sizeof(VARIANT)+3)/sizeof(DWORD);
655 case VT_USERDEFINED:
657 ITypeInfo *tinfo2;
658 TYPEATTR *tattr;
659 HRESULT hres;
660 DWORD ret;
662 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
663 if (FAILED(hres))
664 return 0; /* should fail critically in serialize_param */
665 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
666 ret = (tattr->cbSizeInstance+3)/sizeof(DWORD);
667 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
668 ITypeInfo_Release(tinfo2);
669 return ret;
671 default:
672 return 1;
676 /* how much space do we use on the heap (in bytes) */
677 static int
678 _xsize(const TYPEDESC *td, ITypeInfo *tinfo) {
679 switch (td->vt) {
680 case VT_DATE:
681 return sizeof(DATE);
682 case VT_CY:
683 return sizeof(CY);
684 case VT_VARIANT:
685 return sizeof(VARIANT);
686 case VT_CARRAY: {
687 int i, arrsize = 1;
688 const ARRAYDESC *adesc = td->u.lpadesc;
690 for (i=0;i<adesc->cDims;i++)
691 arrsize *= adesc->rgbounds[i].cElements;
692 return arrsize*_xsize(&adesc->tdescElem, tinfo);
694 case VT_UI8:
695 case VT_I8:
696 case VT_R8:
697 return 8;
698 case VT_UI2:
699 case VT_I2:
700 case VT_BOOL:
701 return 2;
702 case VT_UI1:
703 case VT_I1:
704 return 1;
705 case VT_USERDEFINED:
707 ITypeInfo *tinfo2;
708 TYPEATTR *tattr;
709 HRESULT hres;
710 DWORD ret;
712 hres = ITypeInfo_GetRefTypeInfo(tinfo,td->u.hreftype,&tinfo2);
713 if (FAILED(hres))
714 return 0;
715 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
716 ret = tattr->cbSizeInstance;
717 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
718 ITypeInfo_Release(tinfo2);
719 return ret;
721 default:
722 return 4;
726 /* Whether we pass this type by reference or by value */
727 static BOOL
728 _passbyref(const TYPEDESC *td, ITypeInfo *tinfo) {
729 return (td->vt == VT_USERDEFINED ||
730 td->vt == VT_VARIANT ||
731 td->vt == VT_PTR);
734 static HRESULT
735 serialize_param(
736 ITypeInfo *tinfo,
737 BOOL writeit,
738 BOOL debugout,
739 BOOL dealloc,
740 TYPEDESC *tdesc,
741 DWORD *arg,
742 marshal_state *buf)
744 HRESULT hres = S_OK;
745 VARTYPE vartype;
747 TRACE("(tdesc.vt %s)\n",debugstr_vt(tdesc->vt));
749 vartype = tdesc->vt;
750 if ((vartype & 0xf000) == VT_ARRAY)
751 vartype = VT_SAFEARRAY;
753 switch (vartype) {
754 case VT_DATE:
755 case VT_I8:
756 case VT_UI8:
757 case VT_R8:
758 case VT_CY:
759 hres = S_OK;
760 if (debugout) TRACE_(olerelay)("%x%x\n",arg[0],arg[1]);
761 if (writeit)
762 hres = xbuf_add(buf,(LPBYTE)arg,8);
763 return hres;
764 case VT_ERROR:
765 case VT_INT:
766 case VT_UINT:
767 case VT_I4:
768 case VT_R4:
769 case VT_UI4:
770 hres = S_OK;
771 if (debugout) TRACE_(olerelay)("%x\n",*arg);
772 if (writeit)
773 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
774 return hres;
775 case VT_I2:
776 case VT_UI2:
777 case VT_BOOL:
778 hres = S_OK;
779 if (debugout) TRACE_(olerelay)("%04x\n",*arg & 0xffff);
780 if (writeit)
781 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
782 return hres;
783 case VT_I1:
784 case VT_UI1:
785 hres = S_OK;
786 if (debugout) TRACE_(olerelay)("%02x\n",*arg & 0xff);
787 if (writeit)
788 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
789 return hres;
790 case VT_VARIANT: {
791 if (debugout) TRACE_(olerelay)("%s", debugstr_variant((VARIANT *)arg));
792 if (writeit)
794 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
795 ULONG size = VARIANT_UserSize(&flags, buf->curoff, (VARIANT *)arg);
796 xbuf_resize(buf, size);
797 VARIANT_UserMarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
798 buf->curoff = size;
800 if (dealloc)
802 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
803 VARIANT_UserFree(&flags, (VARIANT *)arg);
805 return S_OK;
807 case VT_BSTR: {
808 if (writeit && debugout) {
809 if (*arg)
810 TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
811 else
812 TRACE_(olerelay)("<bstr NULL>");
814 if (writeit)
816 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
817 ULONG size = BSTR_UserSize(&flags, buf->curoff, (BSTR *)arg);
818 xbuf_resize(buf, size);
819 BSTR_UserMarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
820 buf->curoff = size;
822 if (dealloc)
824 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
825 BSTR_UserFree(&flags, (BSTR *)arg);
827 return S_OK;
829 case VT_PTR: {
830 DWORD cookie;
831 BOOL derefhere = TRUE;
833 if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
834 ITypeInfo *tinfo2;
835 TYPEATTR *tattr;
837 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
838 if (hres) {
839 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
840 return hres;
842 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
843 switch (tattr->typekind) {
844 case TKIND_ALIAS:
845 if (tattr->tdescAlias.vt == VT_USERDEFINED)
847 DWORD href = tattr->tdescAlias.u.hreftype;
848 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
849 ITypeInfo_Release(tinfo2);
850 hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
851 if (hres) {
852 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
853 return hres;
855 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
856 derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
858 break;
859 case TKIND_ENUM: /* confirmed */
860 case TKIND_RECORD: /* FIXME: mostly untested */
861 break;
862 case TKIND_DISPATCH: /* will be done in VT_USERDEFINED case */
863 case TKIND_INTERFACE: /* will be done in VT_USERDEFINED case */
864 derefhere=FALSE;
865 break;
866 default:
867 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
868 derefhere=FALSE;
869 break;
871 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
872 ITypeInfo_Release(tinfo2);
875 if (debugout) TRACE_(olerelay)("*");
876 /* Write always, so the other side knows when it gets a NULL pointer.
878 cookie = *arg ? 0x42424242 : 0;
879 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
880 if (hres)
881 return hres;
882 if (!*arg) {
883 if (debugout) TRACE_(olerelay)("NULL");
884 return S_OK;
886 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
887 if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
888 return hres;
890 case VT_UNKNOWN:
891 if (debugout) TRACE_(olerelay)("unk(0x%x)",*arg);
892 if (writeit)
893 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
894 if (dealloc && *(IUnknown **)arg)
895 IUnknown_Release((LPUNKNOWN)*arg);
896 return hres;
897 case VT_DISPATCH:
898 if (debugout) TRACE_(olerelay)("idisp(0x%x)",*arg);
899 if (writeit)
900 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
901 if (dealloc && *(IUnknown **)arg)
902 IUnknown_Release((LPUNKNOWN)*arg);
903 return hres;
904 case VT_VOID:
905 if (debugout) TRACE_(olerelay)("<void>");
906 return S_OK;
907 case VT_USERDEFINED: {
908 ITypeInfo *tinfo2;
909 TYPEATTR *tattr;
911 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
912 if (hres) {
913 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
914 return hres;
916 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
917 switch (tattr->typekind) {
918 case TKIND_DISPATCH:
919 case TKIND_INTERFACE:
920 if (writeit)
921 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
922 if (dealloc)
923 IUnknown_Release((LPUNKNOWN)arg);
924 break;
925 case TKIND_RECORD: {
926 int i;
927 if (debugout) TRACE_(olerelay)("{");
928 for (i=0;i<tattr->cVars;i++) {
929 VARDESC *vdesc;
930 ELEMDESC *elem2;
931 TYPEDESC *tdesc2;
933 hres = ITypeInfo_GetVarDesc(tinfo2, i, &vdesc);
934 if (hres) {
935 ERR("Could not get vardesc of %d\n",i);
936 return hres;
938 elem2 = &vdesc->elemdescVar;
939 tdesc2 = &elem2->tdesc;
940 hres = serialize_param(
941 tinfo2,
942 writeit,
943 debugout,
944 dealloc,
945 tdesc2,
946 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
949 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
950 if (hres!=S_OK)
951 return hres;
952 if (debugout && (i<(tattr->cVars-1)))
953 TRACE_(olerelay)(",");
955 if (debugout) TRACE_(olerelay)("}");
956 break;
958 case TKIND_ALIAS:
959 hres = serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
960 break;
961 case TKIND_ENUM:
962 hres = S_OK;
963 if (debugout) TRACE_(olerelay)("%x",*arg);
964 if (writeit)
965 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
966 break;
967 default:
968 FIXME("Unhandled typekind %d\n",tattr->typekind);
969 hres = E_FAIL;
970 break;
972 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
973 ITypeInfo_Release(tinfo2);
974 return hres;
976 case VT_CARRAY: {
977 ARRAYDESC *adesc = tdesc->u.lpadesc;
978 int i, arrsize = 1;
980 if (debugout) TRACE_(olerelay)("carr");
981 for (i=0;i<adesc->cDims;i++) {
982 if (debugout) TRACE_(olerelay)("[%d]",adesc->rgbounds[i].cElements);
983 arrsize *= adesc->rgbounds[i].cElements;
985 if (debugout) TRACE_(olerelay)("(vt %s)",debugstr_vt(adesc->tdescElem.vt));
986 if (debugout) TRACE_(olerelay)("[");
987 for (i=0;i<arrsize;i++) {
988 LPBYTE base = _passbyref(&adesc->tdescElem, tinfo) ? (LPBYTE) *arg : (LPBYTE) arg;
989 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)base+i*_xsize(&adesc->tdescElem, tinfo)), buf);
990 if (hres)
991 return hres;
992 if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
994 if (debugout) TRACE_(olerelay)("]");
995 if (dealloc)
996 HeapFree(GetProcessHeap(), 0, *(void **)arg);
997 return S_OK;
999 case VT_SAFEARRAY: {
1000 if (writeit)
1002 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1003 ULONG size = LPSAFEARRAY_UserSize(&flags, buf->curoff, (LPSAFEARRAY *)arg);
1004 xbuf_resize(buf, size);
1005 LPSAFEARRAY_UserMarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1006 buf->curoff = size;
1008 if (dealloc)
1010 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1011 LPSAFEARRAY_UserFree(&flags, (LPSAFEARRAY *)arg);
1013 return S_OK;
1015 default:
1016 ERR("Unhandled marshal type %d.\n",tdesc->vt);
1017 return S_OK;
1021 static HRESULT
1022 deserialize_param(
1023 ITypeInfo *tinfo,
1024 BOOL readit,
1025 BOOL debugout,
1026 BOOL alloc,
1027 TYPEDESC *tdesc,
1028 DWORD *arg,
1029 marshal_state *buf)
1031 HRESULT hres = S_OK;
1032 VARTYPE vartype;
1034 TRACE("vt %s at %p\n",debugstr_vt(tdesc->vt),arg);
1036 vartype = tdesc->vt;
1037 if ((vartype & 0xf000) == VT_ARRAY)
1038 vartype = VT_SAFEARRAY;
1040 while (1) {
1041 switch (vartype) {
1042 case VT_VARIANT: {
1043 if (readit)
1045 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1046 unsigned char *buffer;
1047 buffer = VARIANT_UserUnmarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
1048 buf->curoff = buffer - buf->base;
1050 return S_OK;
1052 case VT_DATE:
1053 case VT_I8:
1054 case VT_UI8:
1055 case VT_R8:
1056 case VT_CY:
1057 if (readit) {
1058 hres = xbuf_get(buf,(LPBYTE)arg,8);
1059 if (hres) ERR("Failed to read integer 8 byte\n");
1061 if (debugout) TRACE_(olerelay)("%x%x",arg[0],arg[1]);
1062 return hres;
1063 case VT_ERROR:
1064 case VT_I4:
1065 case VT_INT:
1066 case VT_UINT:
1067 case VT_R4:
1068 case VT_UI4:
1069 if (readit) {
1070 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1071 if (hres) ERR("Failed to read integer 4 byte\n");
1073 if (debugout) TRACE_(olerelay)("%x",*arg);
1074 return hres;
1075 case VT_I2:
1076 case VT_UI2:
1077 case VT_BOOL:
1078 if (readit) {
1079 DWORD x;
1080 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
1081 if (hres) ERR("Failed to read integer 4 byte\n");
1082 memcpy(arg,&x,2);
1084 if (debugout) TRACE_(olerelay)("%04x",*arg & 0xffff);
1085 return hres;
1086 case VT_I1:
1087 case VT_UI1:
1088 if (readit) {
1089 DWORD x;
1090 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
1091 if (hres) ERR("Failed to read integer 4 byte\n");
1092 memcpy(arg,&x,1);
1094 if (debugout) TRACE_(olerelay)("%02x",*arg & 0xff);
1095 return hres;
1096 case VT_BSTR: {
1097 if (readit)
1099 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1100 unsigned char *buffer;
1101 buffer = BSTR_UserUnmarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
1102 buf->curoff = buffer - buf->base;
1103 if (debugout) TRACE_(olerelay)("%s",debugstr_w(*(BSTR *)arg));
1105 return S_OK;
1107 case VT_PTR: {
1108 DWORD cookie;
1109 BOOL derefhere = TRUE;
1111 if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
1112 ITypeInfo *tinfo2;
1113 TYPEATTR *tattr;
1115 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
1116 if (hres) {
1117 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1118 return hres;
1120 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1121 switch (tattr->typekind) {
1122 case TKIND_ALIAS:
1123 if (tattr->tdescAlias.vt == VT_USERDEFINED)
1125 DWORD href = tattr->tdescAlias.u.hreftype;
1126 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
1127 ITypeInfo_Release(tinfo2);
1128 hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
1129 if (hres) {
1130 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1131 return hres;
1133 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1134 derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
1136 break;
1137 case TKIND_ENUM: /* confirmed */
1138 case TKIND_RECORD: /* FIXME: mostly untested */
1139 break;
1140 case TKIND_DISPATCH: /* will be done in VT_USERDEFINED case */
1141 case TKIND_INTERFACE: /* will be done in VT_USERDEFINED case */
1142 derefhere=FALSE;
1143 break;
1144 default:
1145 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
1146 derefhere=FALSE;
1147 break;
1149 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1150 ITypeInfo_Release(tinfo2);
1152 /* read it in all cases, we need to know if we have
1153 * NULL pointer or not.
1155 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1156 if (hres) {
1157 ERR("Failed to load pointer cookie.\n");
1158 return hres;
1160 if (cookie != 0x42424242) {
1161 /* we read a NULL ptr from the remote side */
1162 if (debugout) TRACE_(olerelay)("NULL");
1163 *arg = 0;
1164 return S_OK;
1166 if (debugout) TRACE_(olerelay)("*");
1167 if (alloc) {
1168 /* Allocate space for the referenced struct */
1169 if (derefhere)
1170 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo));
1172 if (derefhere)
1173 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
1174 else
1175 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
1177 case VT_UNKNOWN:
1178 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
1179 if (alloc)
1180 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
1181 hres = S_OK;
1182 if (readit)
1183 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
1184 if (debugout)
1185 TRACE_(olerelay)("unk(%p)",arg);
1186 return hres;
1187 case VT_DISPATCH:
1188 hres = S_OK;
1189 if (readit)
1190 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
1191 if (debugout)
1192 TRACE_(olerelay)("idisp(%p)",arg);
1193 return hres;
1194 case VT_VOID:
1195 if (debugout) TRACE_(olerelay)("<void>");
1196 return S_OK;
1197 case VT_USERDEFINED: {
1198 ITypeInfo *tinfo2;
1199 TYPEATTR *tattr;
1201 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1202 if (hres) {
1203 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
1204 return hres;
1206 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1207 if (hres) {
1208 ERR("Could not get typeattr in VT_USERDEFINED.\n");
1209 } else {
1210 switch (tattr->typekind) {
1211 case TKIND_DISPATCH:
1212 case TKIND_INTERFACE:
1213 if (readit)
1214 hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
1215 break;
1216 case TKIND_RECORD: {
1217 int i;
1219 if (debugout) TRACE_(olerelay)("{");
1220 for (i=0;i<tattr->cVars;i++) {
1221 VARDESC *vdesc;
1223 hres = ITypeInfo_GetVarDesc(tinfo2, i, &vdesc);
1224 if (hres) {
1225 ERR("Could not get vardesc of %d\n",i);
1226 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1227 ITypeInfo_Release(tinfo2);
1228 return hres;
1230 hres = deserialize_param(
1231 tinfo2,
1232 readit,
1233 debugout,
1234 alloc,
1235 &vdesc->elemdescVar.tdesc,
1236 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
1239 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
1240 if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1242 if (debugout) TRACE_(olerelay)("}");
1243 break;
1245 case TKIND_ALIAS:
1246 hres = deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
1247 break;
1248 case TKIND_ENUM:
1249 if (readit) {
1250 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1251 if (hres) ERR("Failed to read enum (4 byte)\n");
1253 if (debugout) TRACE_(olerelay)("%x",*arg);
1254 break;
1255 default:
1256 ERR("Unhandled typekind %d\n",tattr->typekind);
1257 hres = E_FAIL;
1258 break;
1260 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1262 if (hres)
1263 ERR("failed to stuballoc in TKIND_RECORD.\n");
1264 ITypeInfo_Release(tinfo2);
1265 return hres;
1267 case VT_CARRAY: {
1268 /* arg is pointing to the start of the array. */
1269 LPBYTE base = (LPBYTE) arg;
1270 ARRAYDESC *adesc = tdesc->u.lpadesc;
1271 int arrsize,i;
1272 arrsize = 1;
1273 if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1274 for (i=0;i<adesc->cDims;i++)
1275 arrsize *= adesc->rgbounds[i].cElements;
1276 if (_passbyref(&adesc->tdescElem, tinfo))
1278 base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo) * arrsize);
1279 *arg = (DWORD) base;
1281 for (i=0;i<arrsize;i++)
1282 deserialize_param(
1283 tinfo,
1284 readit,
1285 debugout,
1286 alloc,
1287 &adesc->tdescElem,
1288 (DWORD*)(base + i*_xsize(&adesc->tdescElem, tinfo)),
1291 return S_OK;
1293 case VT_SAFEARRAY: {
1294 if (readit)
1296 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1297 unsigned char *buffer;
1298 buffer = LPSAFEARRAY_UserUnmarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1299 buf->curoff = buffer - buf->base;
1301 return S_OK;
1303 default:
1304 ERR("No handler for VT type %d!\n",tdesc->vt);
1305 return S_OK;
1310 /* Retrieves a function's funcdesc, searching back into inherited interfaces. */
1311 static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, const FUNCDESC **fdesc,
1312 BSTR *iname, BSTR *fname, UINT *num)
1314 HRESULT hr;
1315 UINT i, impl_types;
1316 UINT inherited_funcs = 0;
1317 TYPEATTR *attr;
1319 if (fname) *fname = NULL;
1320 if (iname) *iname = NULL;
1321 if (num) *num = 0;
1322 *tactual = NULL;
1324 hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
1325 if (FAILED(hr))
1327 ERR("GetTypeAttr failed with %x\n",hr);
1328 return hr;
1331 if(attr->typekind == TKIND_DISPATCH)
1333 if(attr->wTypeFlags & TYPEFLAG_FDUAL)
1335 HREFTYPE href;
1336 ITypeInfo *tinfo2;
1338 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
1339 if(FAILED(hr))
1341 ERR("Cannot get interface href from dual dispinterface\n");
1342 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1343 return hr;
1345 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1346 if(FAILED(hr))
1348 ERR("Cannot get interface from dual dispinterface\n");
1349 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1350 return hr;
1352 hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
1353 ITypeInfo_Release(tinfo2);
1354 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1355 return hr;
1357 ERR("Shouldn't be called with a non-dual dispinterface\n");
1358 return E_FAIL;
1361 impl_types = attr->cImplTypes;
1362 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1364 for (i = 0; i < impl_types; i++)
1366 HREFTYPE href;
1367 ITypeInfo *pSubTypeInfo;
1368 UINT sub_funcs;
1370 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
1371 if (FAILED(hr)) return hr;
1372 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
1373 if (FAILED(hr)) return hr;
1375 hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
1376 inherited_funcs += sub_funcs;
1377 ITypeInfo_Release(pSubTypeInfo);
1378 if(SUCCEEDED(hr)) return hr;
1380 if(iMethod < inherited_funcs)
1382 ERR("shouldn't be here\n");
1383 return E_INVALIDARG;
1386 for(i = inherited_funcs; i <= iMethod; i++)
1388 hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
1389 if(FAILED(hr))
1391 if(num) *num = i;
1392 return hr;
1396 /* found it. We don't care about num so zero it */
1397 if(num) *num = 0;
1398 *tactual = tinfo;
1399 ITypeInfo_AddRef(*tactual);
1400 if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1401 if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1402 return S_OK;
1405 static inline BOOL is_in_elem(const ELEMDESC *elem)
1407 return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
1410 static inline BOOL is_out_elem(const ELEMDESC *elem)
1412 return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
1415 static DWORD WINAPI xCall(int method, void **args)
1417 TMProxyImpl *tpinfo = args[0];
1418 DWORD *xargs;
1419 const FUNCDESC *fdesc;
1420 HRESULT hres;
1421 int i;
1422 marshal_state buf;
1423 RPCOLEMESSAGE msg;
1424 ULONG status;
1425 BSTR fname,iname;
1426 BSTR names[10];
1427 UINT nrofnames;
1428 DWORD remoteresult = 0;
1429 ITypeInfo *tinfo;
1430 IRpcChannelBuffer *chanbuf;
1432 EnterCriticalSection(&tpinfo->crit);
1434 hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1435 if (hres) {
1436 ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1437 LeaveCriticalSection(&tpinfo->crit);
1438 return E_FAIL;
1441 if (!tpinfo->chanbuf)
1443 WARN("Tried to use disconnected proxy\n");
1444 ITypeInfo_Release(tinfo);
1445 LeaveCriticalSection(&tpinfo->crit);
1446 return RPC_E_DISCONNECTED;
1448 chanbuf = tpinfo->chanbuf;
1449 IRpcChannelBuffer_AddRef(chanbuf);
1451 LeaveCriticalSection(&tpinfo->crit);
1453 if (TRACE_ON(olerelay)) {
1454 TRACE_(olerelay)("->");
1455 if (iname)
1456 TRACE_(olerelay)("%s:",relaystr(iname));
1457 if (fname)
1458 TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1459 else
1460 TRACE_(olerelay)("%d",method);
1461 TRACE_(olerelay)("(");
1464 SysFreeString(iname);
1465 SysFreeString(fname);
1467 memset(&buf,0,sizeof(buf));
1469 /* normal typelib driven serializing */
1471 /* Need them for hack below */
1472 memset(names,0,sizeof(names));
1473 if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1474 nrofnames = 0;
1475 if (nrofnames > sizeof(names)/sizeof(names[0]))
1476 ERR("Need more names!\n");
1478 xargs = (DWORD *)(args + 1);
1479 for (i=0;i<fdesc->cParams;i++) {
1480 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1481 if (TRACE_ON(olerelay)) {
1482 if (i) TRACE_(olerelay)(",");
1483 if (i+1<nrofnames && names[i+1])
1484 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1486 /* No need to marshal other data than FIN and any VT_PTR. */
1487 if (!is_in_elem(elem))
1489 if (elem->tdesc.vt != VT_PTR)
1491 xargs+=_argsize(&elem->tdesc, tinfo);
1492 TRACE_(olerelay)("[out]");
1493 continue;
1495 else
1497 memset( *(void **)xargs, 0, _xsize( elem->tdesc.u.lptdesc, tinfo ) );
1501 hres = serialize_param(
1502 tinfo,
1503 is_in_elem(elem),
1504 TRACE_ON(olerelay),
1505 FALSE,
1506 &elem->tdesc,
1507 xargs,
1508 &buf
1511 if (hres) {
1512 ERR("Failed to serialize param, hres %x\n",hres);
1513 break;
1515 xargs+=_argsize(&elem->tdesc, tinfo);
1517 TRACE_(olerelay)(")");
1519 memset(&msg,0,sizeof(msg));
1520 msg.cbBuffer = buf.curoff;
1521 msg.iMethod = method;
1522 hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1523 if (hres) {
1524 ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1525 goto exit;
1527 memcpy(msg.Buffer,buf.base,buf.curoff);
1528 TRACE_(olerelay)("\n");
1529 hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1530 if (hres) {
1531 ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1532 goto exit;
1535 TRACE_(olerelay)(" status = %08x (",status);
1536 if (buf.base)
1537 buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1538 else
1539 buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1540 buf.size = msg.cbBuffer;
1541 memcpy(buf.base,msg.Buffer,buf.size);
1542 buf.curoff = 0;
1544 /* generic deserializer using typelib description */
1545 xargs = (DWORD *)(args + 1);
1546 status = S_OK;
1547 for (i=0;i<fdesc->cParams;i++) {
1548 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1550 if (i) TRACE_(olerelay)(",");
1551 if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1553 /* No need to marshal other data than FOUT and any VT_PTR */
1554 if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1555 xargs += _argsize(&elem->tdesc, tinfo);
1556 TRACE_(olerelay)("[in]");
1557 continue;
1559 hres = deserialize_param(
1560 tinfo,
1561 is_out_elem(elem),
1562 TRACE_ON(olerelay),
1563 FALSE,
1564 &(elem->tdesc),
1565 xargs,
1566 &buf
1568 if (hres) {
1569 ERR("Failed to unmarshall param, hres %x\n",hres);
1570 status = hres;
1571 break;
1573 xargs += _argsize(&elem->tdesc, tinfo);
1576 hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1577 if (hres != S_OK)
1578 goto exit;
1579 TRACE_(olerelay)(") = %08x\n", remoteresult);
1581 hres = remoteresult;
1583 exit:
1584 IRpcChannelBuffer_FreeBuffer(chanbuf,&msg);
1585 for (i = 0; i < nrofnames; i++)
1586 SysFreeString(names[i]);
1587 HeapFree(GetProcessHeap(),0,buf.base);
1588 IRpcChannelBuffer_Release(chanbuf);
1589 ITypeInfo_Release(tinfo);
1590 TRACE("-- 0x%08x\n", hres);
1591 return hres;
1594 static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1596 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1598 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1600 if (proxy->outerunknown)
1601 return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1603 FIXME("No interface\n");
1604 return E_NOINTERFACE;
1607 static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1609 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1611 TRACE("\n");
1613 if (proxy->outerunknown)
1614 return IUnknown_AddRef(proxy->outerunknown);
1616 return 2; /* FIXME */
1619 static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1621 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1623 TRACE("\n");
1625 if (proxy->outerunknown)
1626 return IUnknown_Release(proxy->outerunknown);
1628 return 1; /* FIXME */
1631 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1633 TMProxyImpl *This = (TMProxyImpl *)iface;
1635 TRACE("(%p)\n", pctinfo);
1637 return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1640 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1642 TMProxyImpl *This = (TMProxyImpl *)iface;
1644 TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1646 return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1649 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1651 TMProxyImpl *This = (TMProxyImpl *)iface;
1653 TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1655 return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1656 cNames, lcid, rgDispId);
1659 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1660 WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1661 EXCEPINFO * pExcepInfo, UINT * puArgErr)
1663 TMProxyImpl *This = (TMProxyImpl *)iface;
1665 TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1666 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
1667 pExcepInfo, puArgErr);
1669 return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1670 wFlags, pDispParams, pVarResult, pExcepInfo,
1671 puArgErr);
1674 typedef struct
1676 IRpcChannelBuffer IRpcChannelBuffer_iface;
1677 LONG refs;
1678 /* the IDispatch-derived interface we are handling */
1679 IID tmarshal_iid;
1680 IRpcChannelBuffer *pDelegateChannel;
1681 } TMarshalDispatchChannel;
1683 static inline TMarshalDispatchChannel *impl_from_IRpcChannelBuffer(IRpcChannelBuffer *iface)
1685 return CONTAINING_RECORD(iface, TMarshalDispatchChannel, IRpcChannelBuffer_iface);
1688 static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(IRpcChannelBuffer *iface, REFIID riid, LPVOID *ppv)
1690 *ppv = NULL;
1691 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
1693 *ppv = iface;
1694 IRpcChannelBuffer_AddRef(iface);
1695 return S_OK;
1697 return E_NOINTERFACE;
1700 static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
1702 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1703 return InterlockedIncrement(&This->refs);
1706 static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
1708 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1709 ULONG ref;
1711 ref = InterlockedDecrement(&This->refs);
1712 if (ref)
1713 return ref;
1715 IRpcChannelBuffer_Release(This->pDelegateChannel);
1716 HeapFree(GetProcessHeap(), 0, This);
1717 return 0;
1720 static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1722 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1723 TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
1724 /* Note: we are pretending to invoke a method on the interface identified
1725 * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
1726 * without the RPC runtime getting confused by not exporting an IDispatch interface */
1727 return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
1730 static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1732 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1733 TRACE("(%p, %p)\n", olemsg, pstatus);
1734 return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
1737 static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1739 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1740 TRACE("(%p)\n", olemsg);
1741 return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
1744 static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1746 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1747 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1748 return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
1751 static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
1753 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1754 TRACE("()\n");
1755 return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
1758 static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
1760 TMarshalDispatchChannel_QueryInterface,
1761 TMarshalDispatchChannel_AddRef,
1762 TMarshalDispatchChannel_Release,
1763 TMarshalDispatchChannel_GetBuffer,
1764 TMarshalDispatchChannel_SendReceive,
1765 TMarshalDispatchChannel_FreeBuffer,
1766 TMarshalDispatchChannel_GetDestCtx,
1767 TMarshalDispatchChannel_IsConnected
1770 static HRESULT TMarshalDispatchChannel_Create(
1771 IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
1772 IRpcChannelBuffer **ppChannel)
1774 TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1775 if (!This)
1776 return E_OUTOFMEMORY;
1778 This->IRpcChannelBuffer_iface.lpVtbl = &TMarshalDispatchChannelVtbl;
1779 This->refs = 1;
1780 IRpcChannelBuffer_AddRef(pDelegateChannel);
1781 This->pDelegateChannel = pDelegateChannel;
1782 This->tmarshal_iid = *tmarshal_riid;
1784 *ppChannel = &This->IRpcChannelBuffer_iface;
1785 return S_OK;
1789 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
1791 HRESULT hr;
1792 CLSID clsid;
1794 if ((hr = CoGetPSClsid(riid, &clsid)))
1795 return hr;
1796 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
1797 &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1800 static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
1802 int j;
1803 /* nrofargs including This */
1804 int nrofargs = 1;
1805 ITypeInfo *tinfo2;
1806 TMAsmProxy *xasm = proxy->asmstubs + num;
1807 HRESULT hres;
1808 const FUNCDESC *fdesc;
1810 hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
1811 if (hres) {
1812 ERR("GetFuncDesc %x should not fail here.\n",hres);
1813 return hres;
1815 ITypeInfo_Release(tinfo2);
1816 /* some args take more than 4 byte on the stack */
1817 for (j=0;j<fdesc->cParams;j++)
1818 nrofargs += _argsize(&fdesc->lprgelemdescParam[j].tdesc, proxy->tinfo);
1820 #ifdef __i386__
1821 if (fdesc->callconv != CC_STDCALL) {
1822 ERR("calling convention is not stdcall????\n");
1823 return E_FAIL;
1825 /* leal 4(%esp),%eax
1826 * pushl %eax
1827 * pushl <nr>
1828 * call xCall
1829 * lret <nr>
1831 xasm->lealeax = 0x0424448d;
1832 xasm->pushleax = 0x50;
1833 xasm->pushlval = 0x68;
1834 xasm->nr = num;
1835 xasm->lcall = 0xe8;
1836 xasm->xcall = (char *)xCall - (char *)&xasm->lret;
1837 xasm->lret = 0xc2;
1838 xasm->bytestopop = nrofargs * 4;
1839 xasm->nop = 0x9090;
1840 proxy->lpvtbl[fdesc->oVft / sizeof(void *)] = xasm;
1841 #else
1842 FIXME("not implemented on non i386\n");
1843 return E_FAIL;
1844 #endif
1845 return S_OK;
1848 static HRESULT WINAPI
1849 PSFacBuf_CreateProxy(
1850 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1851 IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1853 HRESULT hres;
1854 ITypeInfo *tinfo;
1855 unsigned int i, nroffuncs, vtbl_size;
1856 TMProxyImpl *proxy;
1857 TYPEATTR *typeattr;
1858 BOOL defer_to_dispatch = FALSE;
1860 TRACE("(...%s...)\n",debugstr_guid(riid));
1861 hres = _get_typeinfo_for_iid(riid,&tinfo);
1862 if (hres) {
1863 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1864 return hres;
1867 hres = num_of_funcs(tinfo, &nroffuncs, &vtbl_size);
1868 TRACE("Got %d funcs, vtbl size %d\n", nroffuncs, vtbl_size);
1870 if (FAILED(hres)) {
1871 ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
1872 ITypeInfo_Release(tinfo);
1873 return hres;
1876 proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1877 if (!proxy) return E_OUTOFMEMORY;
1879 proxy->dispatch = NULL;
1880 proxy->dispatch_proxy = NULL;
1881 proxy->outerunknown = pUnkOuter;
1882 proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1883 if (!proxy->asmstubs) {
1884 ERR("Could not commit pages for proxy thunks\n");
1885 CoTaskMemFree(proxy);
1886 return E_OUTOFMEMORY;
1888 proxy->IRpcProxyBuffer_iface.lpVtbl = &tmproxyvtable;
1889 /* one reference for the proxy */
1890 proxy->ref = 1;
1891 proxy->tinfo = tinfo;
1892 proxy->iid = *riid;
1893 proxy->chanbuf = 0;
1895 InitializeCriticalSection(&proxy->crit);
1896 proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
1898 proxy->lpvtbl = HeapAlloc(GetProcessHeap(), 0, vtbl_size);
1900 /* if we derive from IDispatch then defer to its proxy for its methods */
1901 hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
1902 if (hres == S_OK)
1904 if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
1906 IPSFactoryBuffer *factory_buffer;
1907 hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1908 if (hres == S_OK)
1910 hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
1911 &IID_IDispatch, &proxy->dispatch_proxy,
1912 (void **)&proxy->dispatch);
1913 IPSFactoryBuffer_Release(factory_buffer);
1915 if ((hres == S_OK) && (nroffuncs < 7))
1917 ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
1918 hres = E_UNEXPECTED;
1920 if (hres == S_OK)
1922 defer_to_dispatch = TRUE;
1925 ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
1928 for (i=0;i<nroffuncs;i++) {
1929 switch (i) {
1930 case 0:
1931 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
1932 break;
1933 case 1:
1934 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
1935 break;
1936 case 2:
1937 proxy->lpvtbl[i] = ProxyIUnknown_Release;
1938 break;
1939 case 3:
1940 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1941 else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
1942 break;
1943 case 4:
1944 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1945 else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
1946 break;
1947 case 5:
1948 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1949 else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
1950 break;
1951 case 6:
1952 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
1953 else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
1954 break;
1955 default:
1956 hres = init_proxy_entry_point(proxy, i);
1960 if (hres == S_OK)
1962 *ppv = proxy;
1963 *ppProxy = &proxy->IRpcProxyBuffer_iface;
1964 IUnknown_AddRef((IUnknown *)*ppv);
1965 return S_OK;
1967 else
1968 TMProxyImpl_Release(&proxy->IRpcProxyBuffer_iface);
1969 return hres;
1972 typedef struct _TMStubImpl {
1973 IRpcStubBuffer IRpcStubBuffer_iface;
1974 LONG ref;
1976 LPUNKNOWN pUnk;
1977 ITypeInfo *tinfo;
1978 IID iid;
1979 IRpcStubBuffer *dispatch_stub;
1980 BOOL dispatch_derivative;
1981 } TMStubImpl;
1983 static inline TMStubImpl *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
1985 return CONTAINING_RECORD(iface, TMStubImpl, IRpcStubBuffer_iface);
1988 static HRESULT WINAPI
1989 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1991 if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1992 *ppv = iface;
1993 IRpcStubBuffer_AddRef(iface);
1994 return S_OK;
1996 FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1997 return E_NOINTERFACE;
2000 static ULONG WINAPI
2001 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
2003 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2004 ULONG refCount = InterlockedIncrement(&This->ref);
2006 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
2008 return refCount;
2011 static ULONG WINAPI
2012 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
2014 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2015 ULONG refCount = InterlockedDecrement(&This->ref);
2017 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
2019 if (!refCount)
2021 IRpcStubBuffer_Disconnect(iface);
2022 ITypeInfo_Release(This->tinfo);
2023 if (This->dispatch_stub)
2024 IRpcStubBuffer_Release(This->dispatch_stub);
2025 CoTaskMemFree(This);
2027 return refCount;
2030 static HRESULT WINAPI
2031 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
2033 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2035 TRACE("(%p)->(%p)\n", This, pUnkServer);
2037 IUnknown_AddRef(pUnkServer);
2038 This->pUnk = pUnkServer;
2040 if (This->dispatch_stub)
2041 IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);
2043 return S_OK;
2046 static void WINAPI
2047 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
2049 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2051 TRACE("(%p)->()\n", This);
2053 if (This->pUnk)
2055 IUnknown_Release(This->pUnk);
2056 This->pUnk = NULL;
2059 if (This->dispatch_stub)
2060 IRpcStubBuffer_Disconnect(This->dispatch_stub);
2063 static HRESULT WINAPI
2064 TMStubImpl_Invoke(
2065 LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
2067 #ifdef __i386__
2068 int i;
2069 const FUNCDESC *fdesc;
2070 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2071 HRESULT hres;
2072 DWORD *args = NULL, res, *xargs, nrofargs;
2073 marshal_state buf;
2074 UINT nrofnames = 0;
2075 BSTR names[10];
2076 BSTR iname = NULL;
2077 ITypeInfo *tinfo = NULL;
2079 TRACE("...\n");
2081 if (xmsg->iMethod < 3) {
2082 ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
2083 return E_UNEXPECTED;
2086 if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
2088 if (!This->dispatch_stub)
2090 IPSFactoryBuffer *factory_buffer;
2091 hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
2092 if (hres == S_OK)
2094 hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
2095 This->pUnk, &This->dispatch_stub);
2096 IPSFactoryBuffer_Release(factory_buffer);
2098 if (hres != S_OK)
2099 return hres;
2101 return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
2104 memset(&buf,0,sizeof(buf));
2105 buf.size = xmsg->cbBuffer;
2106 buf.base = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
2107 memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
2108 buf.curoff = 0;
2110 hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
2111 if (hres) {
2112 ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
2113 return hres;
2116 if (iname && !lstrcmpW(iname, IDispatchW))
2118 ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
2119 hres = E_UNEXPECTED;
2120 SysFreeString (iname);
2121 goto exit;
2124 SysFreeString (iname);
2126 /* Need them for hack below */
2127 memset(names,0,sizeof(names));
2128 ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
2129 if (nrofnames > sizeof(names)/sizeof(names[0])) {
2130 ERR("Need more names!\n");
2133 /*dump_FUNCDESC(fdesc);*/
2134 nrofargs = 0;
2135 for (i=0;i<fdesc->cParams;i++)
2136 nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo);
2137 args = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(nrofargs+1)*sizeof(DWORD));
2138 if (!args)
2140 hres = E_OUTOFMEMORY;
2141 goto exit;
2144 /* Allocate all stuff used by call. */
2145 xargs = args+1;
2146 for (i=0;i<fdesc->cParams;i++) {
2147 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
2149 hres = deserialize_param(
2150 tinfo,
2151 is_in_elem(elem),
2152 FALSE,
2153 TRUE,
2154 &(elem->tdesc),
2155 xargs,
2156 &buf
2158 xargs += _argsize(&elem->tdesc, tinfo);
2159 if (hres) {
2160 ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2161 break;
2165 args[0] = (DWORD)This->pUnk;
2167 __TRY
2169 res = _invoke(
2170 (*((FARPROC**)args[0]))[fdesc->oVft/4],
2171 fdesc->callconv,
2172 (xargs-args),
2173 args
2176 __EXCEPT_ALL
2178 DWORD dwExceptionCode = GetExceptionCode();
2179 ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2180 if (FAILED(dwExceptionCode))
2181 hres = dwExceptionCode;
2182 else
2183 hres = HRESULT_FROM_WIN32(dwExceptionCode);
2185 __ENDTRY
2187 if (hres != S_OK)
2188 goto exit;
2190 buf.curoff = 0;
2192 xargs = args+1;
2193 for (i=0;i<fdesc->cParams;i++) {
2194 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
2195 hres = serialize_param(
2196 tinfo,
2197 is_out_elem(elem),
2198 FALSE,
2199 TRUE,
2200 &elem->tdesc,
2201 xargs,
2202 &buf
2204 xargs += _argsize(&elem->tdesc, tinfo);
2205 if (hres) {
2206 ERR("Failed to stuballoc param, hres %x\n",hres);
2207 break;
2211 hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2213 if (hres != S_OK)
2214 goto exit;
2216 xmsg->cbBuffer = buf.curoff;
2217 hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
2218 if (hres != S_OK)
2219 ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2221 if (hres == S_OK)
2222 memcpy(xmsg->Buffer, buf.base, buf.curoff);
2224 exit:
2225 for (i = 0; i < nrofnames; i++)
2226 SysFreeString(names[i]);
2228 ITypeInfo_Release(tinfo);
2229 HeapFree(GetProcessHeap(), 0, args);
2231 HeapFree(GetProcessHeap(), 0, buf.base);
2233 TRACE("returning\n");
2234 return hres;
2235 #else
2236 FIXME( "not implemented on non-i386\n" );
2237 return E_FAIL;
2238 #endif
2241 static LPRPCSTUBBUFFER WINAPI
2242 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
2243 FIXME("Huh (%s)?\n",debugstr_guid(riid));
2244 return NULL;
2247 static ULONG WINAPI
2248 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
2249 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2251 FIXME("()\n");
2252 return This->ref; /*FIXME? */
2255 static HRESULT WINAPI
2256 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
2257 return E_NOTIMPL;
2260 static void WINAPI
2261 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
2262 return;
2265 static const IRpcStubBufferVtbl tmstubvtbl = {
2266 TMStubImpl_QueryInterface,
2267 TMStubImpl_AddRef,
2268 TMStubImpl_Release,
2269 TMStubImpl_Connect,
2270 TMStubImpl_Disconnect,
2271 TMStubImpl_Invoke,
2272 TMStubImpl_IsIIDSupported,
2273 TMStubImpl_CountRefs,
2274 TMStubImpl_DebugServerQueryInterface,
2275 TMStubImpl_DebugServerRelease
2278 static HRESULT WINAPI
2279 PSFacBuf_CreateStub(
2280 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
2281 IRpcStubBuffer** ppStub
2283 HRESULT hres;
2284 ITypeInfo *tinfo;
2285 TMStubImpl *stub;
2286 TYPEATTR *typeattr;
2287 IUnknown *obj;
2289 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2291 hres = _get_typeinfo_for_iid(riid,&tinfo);
2292 if (hres) {
2293 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2294 return hres;
2297 /* FIXME: This is not exactly right. We should probably call QI later. */
2298 hres = IUnknown_QueryInterface(pUnkServer, riid, (void**)&obj);
2299 if (FAILED(hres)) {
2300 WARN("Could not get %s iface: %08x\n", debugstr_guid(riid), hres);
2301 obj = pUnkServer;
2302 IUnknown_AddRef(obj);
2305 stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2306 if (!stub) {
2307 IUnknown_Release(obj);
2308 return E_OUTOFMEMORY;
2310 stub->IRpcStubBuffer_iface.lpVtbl = &tmstubvtbl;
2311 stub->ref = 1;
2312 stub->tinfo = tinfo;
2313 stub->dispatch_stub = NULL;
2314 stub->dispatch_derivative = FALSE;
2315 stub->iid = *riid;
2316 hres = IRpcStubBuffer_Connect(&stub->IRpcStubBuffer_iface, obj);
2317 *ppStub = &stub->IRpcStubBuffer_iface;
2318 TRACE("IRpcStubBuffer: %p\n", stub);
2319 if (hres)
2320 ERR("Connect to pUnkServer failed?\n");
2322 /* if we derive from IDispatch then defer to its stub for some of its methods */
2323 hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2324 if (hres == S_OK)
2326 if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2327 stub->dispatch_derivative = TRUE;
2328 ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2331 IUnknown_Release(obj);
2332 return hres;
2335 static const IPSFactoryBufferVtbl psfacbufvtbl = {
2336 PSFacBuf_QueryInterface,
2337 PSFacBuf_AddRef,
2338 PSFacBuf_Release,
2339 PSFacBuf_CreateProxy,
2340 PSFacBuf_CreateStub
2343 static IPSFactoryBuffer psfac = { &psfacbufvtbl };
2345 /***********************************************************************
2346 * TMARSHAL_DllGetClassObject
2348 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid, void **ppv)
2350 return IPSFactoryBuffer_QueryInterface(&psfac, iid, ppv);