c0483fd9d729abeb3dca56813afd74d6c307f1b0
[reactos.git] / reactos / dll / win32 / oleaut32 / tmarshal.c
1 /*
2 * TYPELIB Marshaler
3 *
4 * Copyright 2002,2005 Marcus Meissner
5 *
6 * The olerelay debug channel allows you to see calls marshalled by
7 * the typelib marshaller. It is not a generic COM relaying system.
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #include "precomp.h"
25
26 #include "typelib.h"
27
28 #include <wine/exception.h>
29
30 static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
31
32 WINE_DEFAULT_DEBUG_CHANNEL(ole);
33 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
34
35 static HRESULT TMarshalDispatchChannel_Create(
36 IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
37 IRpcChannelBuffer **ppChannel);
38
39 typedef struct _marshal_state {
40 LPBYTE base;
41 int size;
42 int curoff;
43 } marshal_state;
44
45 /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
46 static char *relaystr(WCHAR *in) {
47 char *tmp = (char *)debugstr_w(in);
48 tmp += 2;
49 tmp[strlen(tmp)-1] = '\0';
50 return tmp;
51 }
52
53 static HRESULT
54 xbuf_resize(marshal_state *buf, DWORD newsize)
55 {
56 if(buf->size >= newsize)
57 return S_FALSE;
58
59 if(buf->base)
60 {
61 buf->base = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf->base, newsize);
62 if(!buf->base)
63 return E_OUTOFMEMORY;
64 }
65 else
66 {
67 buf->base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
68 if(!buf->base)
69 return E_OUTOFMEMORY;
70 }
71 buf->size = newsize;
72 return S_OK;
73 }
74
75 static HRESULT
76 xbuf_add(marshal_state *buf, const BYTE *stuff, DWORD size)
77 {
78 HRESULT hr;
79
80 if(buf->size - buf->curoff < size)
81 {
82 hr = xbuf_resize(buf, buf->size + size + 100);
83 if(FAILED(hr)) return hr;
84 }
85 memcpy(buf->base+buf->curoff,stuff,size);
86 buf->curoff += size;
87 return S_OK;
88 }
89
90 static HRESULT
91 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
92 if (buf->size < buf->curoff+size) return E_FAIL;
93 memcpy(stuff,buf->base+buf->curoff,size);
94 buf->curoff += size;
95 return S_OK;
96 }
97
98 static HRESULT
99 xbuf_skip(marshal_state *buf, DWORD size) {
100 if (buf->size < buf->curoff+size) return E_FAIL;
101 buf->curoff += size;
102 return S_OK;
103 }
104
105 static HRESULT
106 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
107 IStream *pStm;
108 ULARGE_INTEGER newpos;
109 LARGE_INTEGER seekto;
110 ULONG res;
111 HRESULT hres;
112 DWORD xsize;
113
114 TRACE("...%s...\n",debugstr_guid(riid));
115
116 *pUnk = NULL;
117 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
118 if (hres) {
119 ERR("xbuf_get failed\n");
120 return hres;
121 }
122
123 if (xsize == 0) return S_OK;
124
125 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
126 if (hres) {
127 ERR("Stream create failed %x\n",hres);
128 return hres;
129 }
130
131 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
132 if (hres) {
133 ERR("stream write %x\n",hres);
134 IStream_Release(pStm);
135 return hres;
136 }
137
138 memset(&seekto,0,sizeof(seekto));
139 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
140 if (hres) {
141 ERR("Failed Seek %x\n",hres);
142 IStream_Release(pStm);
143 return hres;
144 }
145
146 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
147 if (hres) {
148 ERR("Unmarshalling interface %s failed with %x\n",debugstr_guid(riid),hres);
149 IStream_Release(pStm);
150 return hres;
151 }
152
153 IStream_Release(pStm);
154 return xbuf_skip(buf,xsize);
155 }
156
157 static HRESULT
158 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
159 LPBYTE tempbuf = NULL;
160 IStream *pStm = NULL;
161 STATSTG ststg;
162 ULARGE_INTEGER newpos;
163 LARGE_INTEGER seekto;
164 ULONG res;
165 DWORD xsize;
166 HRESULT hres;
167
168 if (!pUnk) {
169 /* this is valid, if for instance we serialize
170 * a VT_DISPATCH with NULL ptr which apparently
171 * can happen. S_OK to make sure we continue
172 * serializing.
173 */
174 WARN("pUnk is NULL\n");
175 xsize = 0;
176 return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
177 }
178
179 TRACE("...%s...\n",debugstr_guid(riid));
180
181 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
182 if (hres) {
183 ERR("Stream create failed %x\n",hres);
184 goto fail;
185 }
186
187 hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
188 if (hres) {
189 ERR("Marshalling interface %s failed with %x\n", debugstr_guid(riid), hres);
190 goto fail;
191 }
192
193 hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
194 if (hres) {
195 ERR("Stream stat failed\n");
196 goto fail;
197 }
198
199 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
200 memset(&seekto,0,sizeof(seekto));
201 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
202 if (hres) {
203 ERR("Failed Seek %x\n",hres);
204 goto fail;
205 }
206
207 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
208 if (hres) {
209 ERR("Failed Read %x\n",hres);
210 goto fail;
211 }
212
213 xsize = ststg.cbSize.u.LowPart;
214 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
215 hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
216
217 HeapFree(GetProcessHeap(),0,tempbuf);
218 IStream_Release(pStm);
219
220 return hres;
221
222 fail:
223 xsize = 0;
224 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
225 if (pStm) IStream_Release(pStm);
226 HeapFree(GetProcessHeap(), 0, tempbuf);
227 return hres;
228 }
229
230 /********************* OLE Proxy/Stub Factory ********************************/
231 static HRESULT WINAPI
232 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
233 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
234 *ppv = iface;
235 /* No ref counting, static class */
236 return S_OK;
237 }
238 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
239 return E_NOINTERFACE;
240 }
241
242 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
243 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
244
245 struct ifacepsredirect_data
246 {
247 ULONG size;
248 DWORD mask;
249 GUID iid;
250 ULONG nummethods;
251 GUID tlbid;
252 GUID base;
253 ULONG name_len;
254 ULONG name_offset;
255 };
256
257 struct tlibredirect_data
258 {
259 ULONG size;
260 DWORD res;
261 ULONG name_len;
262 ULONG name_offset;
263 LANGID langid;
264 WORD flags;
265 ULONG help_len;
266 ULONG help_offset;
267 WORD major_version;
268 WORD minor_version;
269 };
270
271 static BOOL actctx_get_typelib_module(REFIID riid, WCHAR *module, DWORD len)
272 {
273 struct ifacepsredirect_data *iface;
274 struct tlibredirect_data *tlib;
275 ACTCTX_SECTION_KEYED_DATA data;
276 WCHAR *ptrW;
277
278 data.cbSize = sizeof(data);
279 if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
280 riid, &data))
281 return FALSE;
282
283 iface = (struct ifacepsredirect_data*)data.lpData;
284 if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION,
285 &iface->tlbid, &data))
286 return FALSE;
287
288 tlib = (struct tlibredirect_data*)data.lpData;
289 ptrW = (WCHAR*)((BYTE*)data.lpSectionBase + tlib->name_offset);
290
291 if (tlib->name_len/sizeof(WCHAR) >= len) {
292 ERR("need larger module buffer, %u\n", tlib->name_len);
293 return FALSE;
294 }
295
296 memcpy(module, ptrW, tlib->name_len);
297 module[tlib->name_len/sizeof(WCHAR)] = 0;
298 return TRUE;
299 }
300
301 static HRESULT reg_get_typelib_module(REFIID riid, WCHAR *module, DWORD len)
302 {
303 HKEY ikey;
304 REGSAM opposite = (sizeof(void*) == 8) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
305 BOOL is_wow64;
306 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
307 char tlfn[260];
308 DWORD tlguidlen, verlen, type;
309 LONG tlfnlen, err;
310
311 sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
312 riid->Data1, riid->Data2, riid->Data3,
313 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
314 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
315 );
316
317 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ,&ikey);
318 if (err && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64)
319 && is_wow64))) {
320 err = RegOpenKeyExA(HKEY_CLASSES_ROOT,interfacekey,0,KEY_READ|opposite,&ikey);
321 }
322 if (err) {
323 ERR("No %s key found.\n",interfacekey);
324 return E_FAIL;
325 }
326 tlguidlen = sizeof(tlguid);
327 if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
328 ERR("Getting typelib guid failed.\n");
329 RegCloseKey(ikey);
330 return E_FAIL;
331 }
332 verlen = sizeof(ver);
333 if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
334 ERR("Could not get version value?\n");
335 RegCloseKey(ikey);
336 return E_FAIL;
337 }
338 RegCloseKey(ikey);
339 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win%u",tlguid,ver,(sizeof(void*) == 8) ? 64 : 32);
340 tlfnlen = sizeof(tlfn);
341 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
342 #ifdef _WIN64
343 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
344 tlfnlen = sizeof(tlfn);
345 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
346 #endif
347 ERR("Could not get typelib fn?\n");
348 return E_FAIL;
349 #ifdef _WIN64
350 }
351 #endif
352 }
353 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, module, len);
354 return S_OK;
355 }
356
357 static HRESULT
358 _get_typeinfo_for_iid(REFIID riid, ITypeInfo **typeinfo)
359 {
360 OLECHAR moduleW[260];
361 ITypeLib *typelib;
362 HRESULT hres;
363
364 *typeinfo = NULL;
365
366 moduleW[0] = 0;
367 if (!actctx_get_typelib_module(riid, moduleW, sizeof(moduleW)/sizeof(moduleW[0]))) {
368 hres = reg_get_typelib_module(riid, moduleW, sizeof(moduleW)/sizeof(moduleW[0]));
369 if (FAILED(hres))
370 return hres;
371 }
372
373 hres = LoadTypeLib(moduleW, &typelib);
374 if (hres != S_OK) {
375 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
376 return hres;
377 }
378
379 hres = ITypeLib_GetTypeInfoOfGuid(typelib, riid, typeinfo);
380 ITypeLib_Release(typelib);
381 if (hres != S_OK)
382 ERR("typelib does not contain info for %s\n", debugstr_guid(riid));
383
384 return hres;
385 }
386
387 /*
388 * Determine the number of functions including all inherited functions
389 * and well as the size of the vtbl.
390 * Note for non-dual dispinterfaces we simply return the size of IDispatch.
391 */
392 static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num,
393 unsigned int *vtbl_size)
394 {
395 HRESULT hr;
396 TYPEATTR *attr;
397 ITypeInfo *tinfo2;
398 UINT inherited_funcs = 0, i;
399
400 *num = 0;
401 if(vtbl_size) *vtbl_size = 0;
402
403 hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
404 if (hr)
405 {
406 ERR("GetTypeAttr failed with %x\n", hr);
407 return hr;
408 }
409
410 if(attr->typekind == TKIND_DISPATCH)
411 {
412 if(attr->wTypeFlags & TYPEFLAG_FDUAL)
413 {
414 HREFTYPE href;
415
416 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
417 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
418 if(FAILED(hr))
419 {
420 ERR("Unable to get interface href from dual dispinterface\n");
421 return hr;
422 }
423 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
424 if(FAILED(hr))
425 {
426 ERR("Unable to get interface from dual dispinterface\n");
427 return hr;
428 }
429 hr = num_of_funcs(tinfo2, num, vtbl_size);
430 ITypeInfo_Release(tinfo2);
431 return hr;
432 }
433 else /* non-dual dispinterface */
434 {
435 /* These will be the size of IDispatchVtbl */
436 *num = attr->cbSizeVft / sizeof(void *);
437 if(vtbl_size) *vtbl_size = attr->cbSizeVft;
438 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
439 return hr;
440 }
441 }
442
443 for (i = 0; i < attr->cImplTypes; i++)
444 {
445 HREFTYPE href;
446 ITypeInfo *pSubTypeInfo;
447 UINT sub_funcs;
448
449 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
450 if (FAILED(hr)) goto end;
451 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
452 if (FAILED(hr)) goto end;
453
454 hr = num_of_funcs(pSubTypeInfo, &sub_funcs, NULL);
455 ITypeInfo_Release(pSubTypeInfo);
456
457 if(FAILED(hr)) goto end;
458 inherited_funcs += sub_funcs;
459 }
460
461 *num = inherited_funcs + attr->cFuncs;
462 if(vtbl_size) *vtbl_size = attr->cbSizeVft;
463
464 end:
465 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
466 return hr;
467 }
468
469 #ifdef __i386__
470
471 #include "pshpack1.h"
472 typedef struct _TMAsmProxy {
473 DWORD lealeax;
474 BYTE pushleax;
475 BYTE pushlval;
476 DWORD nr;
477 BYTE lcall;
478 DWORD xcall;
479 BYTE lret;
480 WORD bytestopop;
481 WORD nop;
482 } TMAsmProxy;
483 #include "poppack.h"
484
485 #elif defined(__x86_64__)
486
487 #include "pshpack1.h"
488 typedef struct _TMAsmProxy {
489 BYTE pushq_rbp;
490 BYTE movq_rsp_rbp[3];
491 DWORD subq_0x20_rsp;
492 DWORD movq_rcx_0x10rbp;
493 DWORD movq_rdx_0x18rbp;
494 DWORD movq_r8_0x20rbp;
495 DWORD movq_r9_0x28rbp;
496 BYTE movq_rcx[3];
497 DWORD nr;
498 DWORD leaq_0x10rbp_rdx;
499 WORD movq_rax;
500 void *xcall;
501 WORD callq_rax;
502 BYTE movq_rbp_rsp[3];
503 BYTE popq_rbp;
504 BYTE ret;
505 DWORD nop;
506 } TMAsmProxy;
507 #include "poppack.h"
508
509 #else /* __i386__ */
510 #ifdef _MSC_VER
511 #pragma message("You need to implement stubless proxies for your architecture")
512 #else
513 # warning You need to implement stubless proxies for your architecture
514 #endif
515 typedef struct _TMAsmProxy {
516 char a;
517 } TMAsmProxy;
518 #endif
519
520 typedef struct _TMProxyImpl {
521 LPVOID *lpvtbl;
522 IRpcProxyBuffer IRpcProxyBuffer_iface;
523 LONG ref;
524
525 TMAsmProxy *asmstubs;
526 ITypeInfo* tinfo;
527 IRpcChannelBuffer* chanbuf;
528 IID iid;
529 CRITICAL_SECTION crit;
530 IUnknown *outerunknown;
531 IDispatch *dispatch;
532 IRpcProxyBuffer *dispatch_proxy;
533 } TMProxyImpl;
534
535 static inline TMProxyImpl *impl_from_IRpcProxyBuffer( IRpcProxyBuffer *iface )
536 {
537 return CONTAINING_RECORD(iface, TMProxyImpl, IRpcProxyBuffer_iface);
538 }
539
540 static HRESULT WINAPI
541 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
542 {
543 TRACE("()\n");
544 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
545 *ppv = iface;
546 IRpcProxyBuffer_AddRef(iface);
547 return S_OK;
548 }
549 FIXME("no interface for %s\n",debugstr_guid(riid));
550 return E_NOINTERFACE;
551 }
552
553 static ULONG WINAPI
554 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
555 {
556 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
557 ULONG refCount = InterlockedIncrement(&This->ref);
558
559 TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
560
561 return refCount;
562 }
563
564 static ULONG WINAPI
565 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
566 {
567 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
568 ULONG refCount = InterlockedDecrement(&This->ref);
569
570 TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
571
572 if (!refCount)
573 {
574 if (This->dispatch_proxy) IRpcProxyBuffer_Release(This->dispatch_proxy);
575 This->crit.DebugInfo->Spare[0] = 0;
576 DeleteCriticalSection(&This->crit);
577 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
578 VirtualFree(This->asmstubs, 0, MEM_RELEASE);
579 HeapFree(GetProcessHeap(), 0, This->lpvtbl);
580 ITypeInfo_Release(This->tinfo);
581 CoTaskMemFree(This);
582 }
583 return refCount;
584 }
585
586 static HRESULT WINAPI
587 TMProxyImpl_Connect(
588 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
589 {
590 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
591
592 TRACE("(%p)\n", pRpcChannelBuffer);
593
594 EnterCriticalSection(&This->crit);
595
596 IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
597 This->chanbuf = pRpcChannelBuffer;
598
599 LeaveCriticalSection(&This->crit);
600
601 if (This->dispatch_proxy)
602 {
603 IRpcChannelBuffer *pDelegateChannel;
604 HRESULT hr = TMarshalDispatchChannel_Create(pRpcChannelBuffer, &This->iid, &pDelegateChannel);
605 if (FAILED(hr))
606 return hr;
607 hr = IRpcProxyBuffer_Connect(This->dispatch_proxy, pDelegateChannel);
608 IRpcChannelBuffer_Release(pDelegateChannel);
609 return hr;
610 }
611
612 return S_OK;
613 }
614
615 static void WINAPI
616 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
617 {
618 TMProxyImpl *This = impl_from_IRpcProxyBuffer( iface );
619
620 TRACE("()\n");
621
622 EnterCriticalSection(&This->crit);
623
624 IRpcChannelBuffer_Release(This->chanbuf);
625 This->chanbuf = NULL;
626
627 LeaveCriticalSection(&This->crit);
628
629 if (This->dispatch_proxy)
630 IRpcProxyBuffer_Disconnect(This->dispatch_proxy);
631 }
632
633
634 static const IRpcProxyBufferVtbl tmproxyvtable = {
635 TMProxyImpl_QueryInterface,
636 TMProxyImpl_AddRef,
637 TMProxyImpl_Release,
638 TMProxyImpl_Connect,
639 TMProxyImpl_Disconnect
640 };
641
642 /* how much space do we use on stack in DWORD_PTR steps. */
643 static int
644 _argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
645 DWORD ret;
646 switch (tdesc->vt) {
647 case VT_I8:
648 case VT_UI8:
649 ret = 8;
650 break;
651 case VT_R8:
652 ret = sizeof(double);
653 break;
654 case VT_CY:
655 ret = sizeof(CY);
656 break;
657 case VT_DATE:
658 ret = sizeof(DATE);
659 break;
660 case VT_DECIMAL:
661 ret = sizeof(DECIMAL);
662 break;
663 case VT_VARIANT:
664 ret = sizeof(VARIANT);
665 break;
666 case VT_USERDEFINED:
667 {
668 ITypeInfo *tinfo2;
669 TYPEATTR *tattr;
670 HRESULT hres;
671
672 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
673 if (FAILED(hres))
674 return 0; /* should fail critically in serialize_param */
675 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
676 ret = tattr->cbSizeInstance;
677 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
678 ITypeInfo_Release(tinfo2);
679 break;
680 }
681 default:
682 ret = sizeof(DWORD_PTR);
683 break;
684 }
685
686 return (ret + sizeof(DWORD_PTR) - 1) / sizeof(DWORD_PTR);
687 }
688
689 /* how much space do we use on the heap (in bytes) */
690 static int
691 _xsize(const TYPEDESC *td, ITypeInfo *tinfo) {
692 switch (td->vt) {
693 case VT_DATE:
694 return sizeof(DATE);
695 case VT_CY:
696 return sizeof(CY);
697 case VT_VARIANT:
698 return sizeof(VARIANT);
699 case VT_CARRAY: {
700 int i, arrsize = 1;
701 const ARRAYDESC *adesc = td->u.lpadesc;
702
703 for (i=0;i<adesc->cDims;i++)
704 arrsize *= adesc->rgbounds[i].cElements;
705 return arrsize*_xsize(&adesc->tdescElem, tinfo);
706 }
707 case VT_UI8:
708 case VT_I8:
709 case VT_R8:
710 return 8;
711 case VT_UI2:
712 case VT_I2:
713 case VT_BOOL:
714 return 2;
715 case VT_UI1:
716 case VT_I1:
717 return 1;
718 case VT_USERDEFINED:
719 {
720 ITypeInfo *tinfo2;
721 TYPEATTR *tattr;
722 HRESULT hres;
723 DWORD ret;
724
725 hres = ITypeInfo_GetRefTypeInfo(tinfo,td->u.hreftype,&tinfo2);
726 if (FAILED(hres))
727 return 0;
728 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
729 ret = tattr->cbSizeInstance;
730 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
731 ITypeInfo_Release(tinfo2);
732 return ret;
733 }
734 default:
735 return sizeof(DWORD_PTR);
736 }
737 }
738
739 /* Whether we pass this type by reference or by value */
740 static BOOL
741 _passbyref(const TYPEDESC *td, ITypeInfo *tinfo) {
742 return (td->vt == VT_USERDEFINED ||
743 td->vt == VT_VARIANT ||
744 td->vt == VT_PTR);
745 }
746
747 static HRESULT
748 serialize_param(
749 ITypeInfo *tinfo,
750 BOOL writeit,
751 BOOL debugout,
752 BOOL dealloc,
753 TYPEDESC *tdesc,
754 DWORD_PTR *arg,
755 marshal_state *buf)
756 {
757 HRESULT hres = S_OK;
758 VARTYPE vartype;
759
760 TRACE("(tdesc.vt %s)\n",debugstr_vt(tdesc->vt));
761
762 vartype = tdesc->vt;
763 if ((vartype & 0xf000) == VT_ARRAY)
764 vartype = VT_SAFEARRAY;
765
766 switch (vartype) {
767 case VT_DATE:
768 case VT_I8:
769 case VT_UI8:
770 case VT_R8:
771 case VT_CY:
772 hres = S_OK;
773 if (debugout) TRACE_(olerelay)("%s\n", wine_dbgstr_longlong(*(ULONGLONG *)arg));
774 if (writeit)
775 hres = xbuf_add(buf,(LPBYTE)arg,8);
776 return hres;
777 case VT_ERROR:
778 case VT_INT:
779 case VT_UINT:
780 case VT_I4:
781 case VT_R4:
782 case VT_UI4:
783 hres = S_OK;
784 if (debugout) TRACE_(olerelay)("%x\n", *(DWORD *)arg);
785 if (writeit)
786 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
787 return hres;
788 case VT_I2:
789 case VT_UI2:
790 case VT_BOOL:
791 hres = S_OK;
792 if (debugout) TRACE_(olerelay)("%04x\n", *(WORD *)arg);
793 if (writeit)
794 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
795 return hres;
796 case VT_I1:
797 case VT_UI1:
798 hres = S_OK;
799 if (debugout) TRACE_(olerelay)("%02x\n", *(BYTE *)arg);
800 if (writeit)
801 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
802 return hres;
803 case VT_VARIANT: {
804 if (debugout) TRACE_(olerelay)("%s", debugstr_variant((VARIANT *)arg));
805 if (writeit)
806 {
807 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
808 ULONG size = VARIANT_UserSize(&flags, buf->curoff, (VARIANT *)arg);
809 xbuf_resize(buf, size);
810 VARIANT_UserMarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
811 buf->curoff = size;
812 }
813 if (dealloc)
814 {
815 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
816 VARIANT_UserFree(&flags, (VARIANT *)arg);
817 }
818 return S_OK;
819 }
820 case VT_BSTR: {
821 if (writeit && debugout) {
822 if (*arg)
823 TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
824 else
825 TRACE_(olerelay)("<bstr NULL>");
826 }
827 if (writeit)
828 {
829 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
830 ULONG size = BSTR_UserSize(&flags, buf->curoff, (BSTR *)arg);
831 xbuf_resize(buf, size);
832 BSTR_UserMarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
833 buf->curoff = size;
834 }
835 if (dealloc)
836 {
837 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
838 BSTR_UserFree(&flags, (BSTR *)arg);
839 }
840 return S_OK;
841 }
842 case VT_PTR: {
843 DWORD cookie;
844 BOOL derefhere = TRUE;
845
846 if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
847 ITypeInfo *tinfo2;
848 TYPEATTR *tattr;
849
850 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&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;
854 }
855 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
856 switch (tattr->typekind) {
857 case TKIND_ALIAS:
858 if (tattr->tdescAlias.vt == VT_USERDEFINED)
859 {
860 DWORD href = tattr->tdescAlias.u.hreftype;
861 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
862 ITypeInfo_Release(tinfo2);
863 hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
864 if (hres) {
865 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
866 return hres;
867 }
868 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
869 derefhere = (tattr->typekind != TKIND_DISPATCH &&
870 tattr->typekind != TKIND_INTERFACE &&
871 tattr->typekind != TKIND_COCLASS);
872 }
873 break;
874 case TKIND_ENUM: /* confirmed */
875 case TKIND_RECORD: /* FIXME: mostly untested */
876 break;
877 case TKIND_DISPATCH: /* will be done in VT_USERDEFINED case */
878 case TKIND_INTERFACE: /* will be done in VT_USERDEFINED case */
879 case TKIND_COCLASS: /* will be done in VT_USERDEFINED case */
880 derefhere=FALSE;
881 break;
882 default:
883 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
884 derefhere=FALSE;
885 break;
886 }
887 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
888 ITypeInfo_Release(tinfo2);
889 }
890
891 if (debugout) TRACE_(olerelay)("*");
892 /* Write always, so the other side knows when it gets a NULL pointer.
893 */
894 cookie = *arg ? 0x42424242 : 0;
895 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
896 if (hres)
897 return hres;
898 if (!*arg) {
899 if (debugout) TRACE_(olerelay)("NULL");
900 return S_OK;
901 }
902 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD_PTR *)*arg,buf);
903 if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
904 return hres;
905 }
906 case VT_UNKNOWN:
907 if (debugout) TRACE_(olerelay)("unk(0x%lx)", *arg);
908 if (writeit)
909 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
910 if (dealloc && *(IUnknown **)arg)
911 IUnknown_Release((LPUNKNOWN)*arg);
912 return hres;
913 case VT_DISPATCH:
914 if (debugout) TRACE_(olerelay)("idisp(0x%lx)", *arg);
915 if (writeit)
916 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
917 if (dealloc && *(IUnknown **)arg)
918 IUnknown_Release((LPUNKNOWN)*arg);
919 return hres;
920 case VT_VOID:
921 if (debugout) TRACE_(olerelay)("<void>");
922 return S_OK;
923 case VT_USERDEFINED: {
924 ITypeInfo *tinfo2;
925 TYPEATTR *tattr;
926
927 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
928 if (hres) {
929 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
930 return hres;
931 }
932 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
933 switch (tattr->typekind) {
934 case TKIND_DISPATCH:
935 case TKIND_INTERFACE:
936 if (writeit)
937 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
938 if (dealloc)
939 IUnknown_Release((LPUNKNOWN)arg);
940 break;
941 case TKIND_COCLASS: {
942 GUID iid = tattr->guid;
943 unsigned int i;
944 int type_flags;
945
946 for(i = 0; i < tattr->cImplTypes; i++) {
947 if(SUCCEEDED(ITypeInfo_GetImplTypeFlags(tinfo2, i, &type_flags)) &&
948 type_flags == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) {
949 ITypeInfo *tinfo3;
950 TYPEATTR *tattr2;
951 HREFTYPE href;
952 if(FAILED(ITypeInfo_GetRefTypeOfImplType(tinfo2, i, &href)))
953 break;
954 if(FAILED(ITypeInfo_GetRefTypeInfo(tinfo2, href, &tinfo3)))
955 break;
956 if(SUCCEEDED(ITypeInfo_GetTypeAttr(tinfo3, &tattr2))) {
957 iid = tattr2->guid;
958 ITypeInfo_ReleaseTypeAttr(tinfo3, tattr2);
959 }
960 ITypeInfo_Release(tinfo3);
961 break;
962 }
963 }
964
965 if(writeit)
966 hres=_marshal_interface(buf, &iid, (LPUNKNOWN)arg);
967 if(dealloc)
968 IUnknown_Release((LPUNKNOWN)arg);
969 break;
970 }
971 case TKIND_RECORD: {
972 int i;
973 if (debugout) TRACE_(olerelay)("{");
974 for (i=0;i<tattr->cVars;i++) {
975 VARDESC *vdesc;
976 ELEMDESC *elem2;
977 TYPEDESC *tdesc2;
978
979 hres = ITypeInfo_GetVarDesc(tinfo2, i, &vdesc);
980 if (hres) {
981 ERR("Could not get vardesc of %d\n",i);
982 return hres;
983 }
984 elem2 = &vdesc->elemdescVar;
985 tdesc2 = &elem2->tdesc;
986 hres = serialize_param(
987 tinfo2,
988 writeit,
989 debugout,
990 dealloc,
991 tdesc2,
992 (DWORD_PTR *)(((LPBYTE)arg)+vdesc->u.oInst),
993 buf
994 );
995 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
996 if (hres!=S_OK)
997 return hres;
998 if (debugout && (i<(tattr->cVars-1)))
999 TRACE_(olerelay)(",");
1000 }
1001 if (debugout) TRACE_(olerelay)("}");
1002 break;
1003 }
1004 case TKIND_ALIAS:
1005 hres = serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
1006 break;
1007 case TKIND_ENUM:
1008 hres = S_OK;
1009 if (debugout) TRACE_(olerelay)("%x", *(DWORD *)arg);
1010 if (writeit)
1011 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
1012 break;
1013 default:
1014 FIXME("Unhandled typekind %d\n",tattr->typekind);
1015 hres = E_FAIL;
1016 break;
1017 }
1018 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1019 ITypeInfo_Release(tinfo2);
1020 return hres;
1021 }
1022 case VT_CARRAY: {
1023 ARRAYDESC *adesc = tdesc->u.lpadesc;
1024 int i, arrsize = 1;
1025
1026 if (debugout) TRACE_(olerelay)("carr");
1027 for (i=0;i<adesc->cDims;i++) {
1028 if (debugout) TRACE_(olerelay)("[%d]",adesc->rgbounds[i].cElements);
1029 arrsize *= adesc->rgbounds[i].cElements;
1030 }
1031 if (debugout) TRACE_(olerelay)("(vt %s)",debugstr_vt(adesc->tdescElem.vt));
1032 if (debugout) TRACE_(olerelay)("[");
1033 for (i=0;i<arrsize;i++) {
1034 LPBYTE base = _passbyref(&adesc->tdescElem, tinfo) ? (LPBYTE) *arg : (LPBYTE) arg;
1035 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD_PTR *)((LPBYTE)base+i*_xsize(&adesc->tdescElem, tinfo)), buf);
1036 if (hres)
1037 return hres;
1038 if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
1039 }
1040 if (debugout) TRACE_(olerelay)("]");
1041 if (dealloc)
1042 HeapFree(GetProcessHeap(), 0, *(void **)arg);
1043 return S_OK;
1044 }
1045 case VT_SAFEARRAY: {
1046 if (writeit)
1047 {
1048 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1049 ULONG size = LPSAFEARRAY_UserSize(&flags, buf->curoff, (LPSAFEARRAY *)arg);
1050 xbuf_resize(buf, size);
1051 LPSAFEARRAY_UserMarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1052 buf->curoff = size;
1053 }
1054 if (dealloc)
1055 {
1056 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1057 LPSAFEARRAY_UserFree(&flags, (LPSAFEARRAY *)arg);
1058 }
1059 return S_OK;
1060 }
1061 default:
1062 ERR("Unhandled marshal type %d.\n",tdesc->vt);
1063 return S_OK;
1064 }
1065 }
1066
1067 static HRESULT
1068 deserialize_param(
1069 ITypeInfo *tinfo,
1070 BOOL readit,
1071 BOOL debugout,
1072 BOOL alloc,
1073 TYPEDESC *tdesc,
1074 DWORD_PTR *arg,
1075 marshal_state *buf)
1076 {
1077 HRESULT hres = S_OK;
1078 VARTYPE vartype;
1079
1080 TRACE("vt %s at %p\n",debugstr_vt(tdesc->vt),arg);
1081
1082 vartype = tdesc->vt;
1083 if ((vartype & 0xf000) == VT_ARRAY)
1084 vartype = VT_SAFEARRAY;
1085
1086 while (1) {
1087 switch (vartype) {
1088 case VT_VARIANT: {
1089 if (readit)
1090 {
1091 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1092 unsigned char *buffer;
1093 buffer = VARIANT_UserUnmarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
1094 buf->curoff = buffer - buf->base;
1095 }
1096 return S_OK;
1097 }
1098 case VT_DATE:
1099 case VT_I8:
1100 case VT_UI8:
1101 case VT_R8:
1102 case VT_CY:
1103 if (readit) {
1104 hres = xbuf_get(buf,(LPBYTE)arg,8);
1105 if (hres) ERR("Failed to read integer 8 byte\n");
1106 }
1107 if (debugout) TRACE_(olerelay)("%s", wine_dbgstr_longlong(*(ULONGLONG *)arg));
1108 return hres;
1109 case VT_ERROR:
1110 case VT_I4:
1111 case VT_INT:
1112 case VT_UINT:
1113 case VT_R4:
1114 case VT_UI4:
1115 if (readit) {
1116 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1117 if (hres) ERR("Failed to read integer 4 byte\n");
1118 }
1119 if (debugout) TRACE_(olerelay)("%x", *(DWORD *)arg);
1120 return hres;
1121 case VT_I2:
1122 case VT_UI2:
1123 case VT_BOOL:
1124 if (readit) {
1125 DWORD x;
1126 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
1127 if (hres) ERR("Failed to read integer 4 byte\n");
1128 memcpy(arg,&x,2);
1129 }
1130 if (debugout) TRACE_(olerelay)("%04x", *(WORD *)arg);
1131 return hres;
1132 case VT_I1:
1133 case VT_UI1:
1134 if (readit) {
1135 DWORD x;
1136 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
1137 if (hres) ERR("Failed to read integer 4 byte\n");
1138 memcpy(arg,&x,1);
1139 }
1140 if (debugout) TRACE_(olerelay)("%02x", *(BYTE *)arg);
1141 return hres;
1142 case VT_BSTR: {
1143 if (readit)
1144 {
1145 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1146 unsigned char *buffer;
1147 buffer = BSTR_UserUnmarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
1148 buf->curoff = buffer - buf->base;
1149 if (debugout) TRACE_(olerelay)("%s",debugstr_w(*(BSTR *)arg));
1150 }
1151 return S_OK;
1152 }
1153 case VT_PTR: {
1154 DWORD cookie;
1155 BOOL derefhere = TRUE;
1156
1157 if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
1158 ITypeInfo *tinfo2;
1159 TYPEATTR *tattr;
1160
1161 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
1162 if (hres) {
1163 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1164 return hres;
1165 }
1166 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1167 switch (tattr->typekind) {
1168 case TKIND_ALIAS:
1169 if (tattr->tdescAlias.vt == VT_USERDEFINED)
1170 {
1171 DWORD href = tattr->tdescAlias.u.hreftype;
1172 ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
1173 ITypeInfo_Release(tinfo2);
1174 hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
1175 if (hres) {
1176 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1177 return hres;
1178 }
1179 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1180 derefhere = (tattr->typekind != TKIND_DISPATCH &&
1181 tattr->typekind != TKIND_INTERFACE &&
1182 tattr->typekind != TKIND_COCLASS);
1183 }
1184 break;
1185 case TKIND_ENUM: /* confirmed */
1186 case TKIND_RECORD: /* FIXME: mostly untested */
1187 break;
1188 case TKIND_DISPATCH: /* will be done in VT_USERDEFINED case */
1189 case TKIND_INTERFACE: /* will be done in VT_USERDEFINED case */
1190 case TKIND_COCLASS: /* will be done in VT_USERDEFINED case */
1191 derefhere=FALSE;
1192 break;
1193 default:
1194 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
1195 derefhere=FALSE;
1196 break;
1197 }
1198 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1199 ITypeInfo_Release(tinfo2);
1200 }
1201 /* read it in all cases, we need to know if we have
1202 * NULL pointer or not.
1203 */
1204 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1205 if (hres) {
1206 ERR("Failed to load pointer cookie.\n");
1207 return hres;
1208 }
1209 if (cookie != 0x42424242) {
1210 /* we read a NULL ptr from the remote side */
1211 if (debugout) TRACE_(olerelay)("NULL");
1212 *arg = 0;
1213 return S_OK;
1214 }
1215 if (debugout) TRACE_(olerelay)("*");
1216 if (alloc) {
1217 /* Allocate space for the referenced struct */
1218 if (derefhere)
1219 *arg=(DWORD_PTR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo));
1220 }
1221 if (derefhere)
1222 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (DWORD_PTR *)*arg, buf);
1223 else
1224 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
1225 }
1226 case VT_UNKNOWN:
1227 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
1228 if (alloc)
1229 *arg=(DWORD_PTR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD_PTR));
1230 hres = S_OK;
1231 if (readit)
1232 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
1233 if (debugout)
1234 TRACE_(olerelay)("unk(%p)",arg);
1235 return hres;
1236 case VT_DISPATCH:
1237 hres = S_OK;
1238 if (readit)
1239 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
1240 if (debugout)
1241 TRACE_(olerelay)("idisp(%p)",arg);
1242 return hres;
1243 case VT_VOID:
1244 if (debugout) TRACE_(olerelay)("<void>");
1245 return S_OK;
1246 case VT_USERDEFINED: {
1247 ITypeInfo *tinfo2;
1248 TYPEATTR *tattr;
1249
1250 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1251 if (hres) {
1252 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
1253 return hres;
1254 }
1255 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1256 if (hres) {
1257 ERR("Could not get typeattr in VT_USERDEFINED.\n");
1258 } else {
1259 switch (tattr->typekind) {
1260 case TKIND_DISPATCH:
1261 case TKIND_INTERFACE:
1262 if (readit)
1263 hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
1264 break;
1265 case TKIND_COCLASS: {
1266 GUID iid = tattr->guid;
1267 unsigned int i;
1268 int type_flags;
1269
1270 for(i = 0; i < tattr->cImplTypes; i++) {
1271 if(SUCCEEDED(ITypeInfo_GetImplTypeFlags(tinfo2, i, &type_flags)) &&
1272 type_flags == (IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT)) {
1273 ITypeInfo *tinfo3;
1274 TYPEATTR *tattr2;
1275 HREFTYPE href;
1276 if(FAILED(ITypeInfo_GetRefTypeOfImplType(tinfo2, i, &href)))
1277 break;
1278 if(FAILED(ITypeInfo_GetRefTypeInfo(tinfo2, href, &tinfo3)))
1279 break;
1280 if(SUCCEEDED(ITypeInfo_GetTypeAttr(tinfo3, &tattr2))) {
1281 iid = tattr2->guid;
1282 ITypeInfo_ReleaseTypeAttr(tinfo3, tattr2);
1283 }
1284 ITypeInfo_Release(tinfo3);
1285 break;
1286 }
1287 }
1288
1289 if(readit)
1290 hres = _unmarshal_interface(buf, &iid, (LPUNKNOWN*)arg);
1291 break;
1292 }
1293 case TKIND_RECORD: {
1294 int i;
1295
1296 if (debugout) TRACE_(olerelay)("{");
1297 for (i=0;i<tattr->cVars;i++) {
1298 VARDESC *vdesc;
1299
1300 hres = ITypeInfo_GetVarDesc(tinfo2, i, &vdesc);
1301 if (hres) {
1302 ERR("Could not get vardesc of %d\n",i);
1303 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1304 ITypeInfo_Release(tinfo2);
1305 return hres;
1306 }
1307 hres = deserialize_param(
1308 tinfo2,
1309 readit,
1310 debugout,
1311 alloc,
1312 &vdesc->elemdescVar.tdesc,
1313 (DWORD_PTR *)(((LPBYTE)arg)+vdesc->u.oInst),
1314 buf
1315 );
1316 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
1317 if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1318 }
1319 if (debugout) TRACE_(olerelay)("}");
1320 break;
1321 }
1322 case TKIND_ALIAS:
1323 hres = deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
1324 break;
1325 case TKIND_ENUM:
1326 if (readit) {
1327 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1328 if (hres) ERR("Failed to read enum (4 byte)\n");
1329 }
1330 if (debugout) TRACE_(olerelay)("%x", *(DWORD *)arg);
1331 break;
1332 default:
1333 ERR("Unhandled typekind %d\n",tattr->typekind);
1334 hres = E_FAIL;
1335 break;
1336 }
1337 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1338 }
1339 if (hres)
1340 ERR("failed to stuballoc in TKIND_RECORD.\n");
1341 ITypeInfo_Release(tinfo2);
1342 return hres;
1343 }
1344 case VT_CARRAY: {
1345 /* arg is pointing to the start of the array. */
1346 LPBYTE base = (LPBYTE) arg;
1347 ARRAYDESC *adesc = tdesc->u.lpadesc;
1348 int arrsize,i;
1349 arrsize = 1;
1350 if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1351 for (i=0;i<adesc->cDims;i++)
1352 arrsize *= adesc->rgbounds[i].cElements;
1353 if (_passbyref(&adesc->tdescElem, tinfo))
1354 {
1355 base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo) * arrsize);
1356 *arg = (DWORD_PTR)base;
1357 }
1358 for (i=0;i<arrsize;i++)
1359 deserialize_param(
1360 tinfo,
1361 readit,
1362 debugout,
1363 alloc,
1364 &adesc->tdescElem,
1365 (DWORD_PTR *)(base + i*_xsize(&adesc->tdescElem, tinfo)),
1366 buf
1367 );
1368 return S_OK;
1369 }
1370 case VT_SAFEARRAY: {
1371 if (readit)
1372 {
1373 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1374 unsigned char *buffer;
1375 buffer = LPSAFEARRAY_UserUnmarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1376 buf->curoff = buffer - buf->base;
1377 }
1378 return S_OK;
1379 }
1380 default:
1381 ERR("No handler for VT type %d!\n",tdesc->vt);
1382 return S_OK;
1383 }
1384 }
1385 }
1386
1387 /* Retrieves a function's funcdesc, searching back into inherited interfaces. */
1388 static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, const FUNCDESC **fdesc,
1389 BSTR *iname, BSTR *fname, UINT *num)
1390 {
1391 HRESULT hr;
1392 UINT i, impl_types;
1393 UINT inherited_funcs = 0;
1394 TYPEATTR *attr;
1395
1396 if (fname) *fname = NULL;
1397 if (iname) *iname = NULL;
1398 if (num) *num = 0;
1399 *tactual = NULL;
1400
1401 hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
1402 if (FAILED(hr))
1403 {
1404 ERR("GetTypeAttr failed with %x\n",hr);
1405 return hr;
1406 }
1407
1408 if(attr->typekind == TKIND_DISPATCH)
1409 {
1410 if(attr->wTypeFlags & TYPEFLAG_FDUAL)
1411 {
1412 HREFTYPE href;
1413 ITypeInfo *tinfo2;
1414
1415 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
1416 if(FAILED(hr))
1417 {
1418 ERR("Cannot get interface href from dual dispinterface\n");
1419 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1420 return hr;
1421 }
1422 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1423 if(FAILED(hr))
1424 {
1425 ERR("Cannot get interface from dual dispinterface\n");
1426 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1427 return hr;
1428 }
1429 hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
1430 ITypeInfo_Release(tinfo2);
1431 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1432 return hr;
1433 }
1434 ERR("Shouldn't be called with a non-dual dispinterface\n");
1435 return E_FAIL;
1436 }
1437
1438 impl_types = attr->cImplTypes;
1439 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1440
1441 for (i = 0; i < impl_types; i++)
1442 {
1443 HREFTYPE href;
1444 ITypeInfo *pSubTypeInfo;
1445 UINT sub_funcs;
1446
1447 hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
1448 if (FAILED(hr)) return hr;
1449 hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
1450 if (FAILED(hr)) return hr;
1451
1452 hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
1453 inherited_funcs += sub_funcs;
1454 ITypeInfo_Release(pSubTypeInfo);
1455 if(SUCCEEDED(hr)) return hr;
1456 }
1457 if(iMethod < inherited_funcs)
1458 {
1459 ERR("shouldn't be here\n");
1460 return E_INVALIDARG;
1461 }
1462
1463 for(i = inherited_funcs; i <= iMethod; i++)
1464 {
1465 hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
1466 if(FAILED(hr))
1467 {
1468 if(num) *num = i;
1469 return hr;
1470 }
1471 }
1472
1473 /* found it. We don't care about num so zero it */
1474 if(num) *num = 0;
1475 *tactual = tinfo;
1476 ITypeInfo_AddRef(*tactual);
1477 if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1478 if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1479 return S_OK;
1480 }
1481
1482 static inline BOOL is_in_elem(const ELEMDESC *elem)
1483 {
1484 return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
1485 }
1486
1487 static inline BOOL is_out_elem(const ELEMDESC *elem)
1488 {
1489 return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
1490 }
1491
1492 static DWORD WINAPI xCall(int method, void **args)
1493 {
1494 TMProxyImpl *tpinfo = args[0];
1495 DWORD_PTR *xargs;
1496 const FUNCDESC *fdesc;
1497 HRESULT hres;
1498 int i;
1499 marshal_state buf;
1500 RPCOLEMESSAGE msg;
1501 ULONG status;
1502 BSTR fname,iname;
1503 BSTR names[10];
1504 UINT nrofnames;
1505 DWORD remoteresult = 0;
1506 ITypeInfo *tinfo;
1507 IRpcChannelBuffer *chanbuf;
1508
1509 EnterCriticalSection(&tpinfo->crit);
1510
1511 hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1512 if (hres) {
1513 ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1514 LeaveCriticalSection(&tpinfo->crit);
1515 return E_FAIL;
1516 }
1517
1518 if (!tpinfo->chanbuf)
1519 {
1520 WARN("Tried to use disconnected proxy\n");
1521 ITypeInfo_Release(tinfo);
1522 LeaveCriticalSection(&tpinfo->crit);
1523 return RPC_E_DISCONNECTED;
1524 }
1525 chanbuf = tpinfo->chanbuf;
1526 IRpcChannelBuffer_AddRef(chanbuf);
1527
1528 LeaveCriticalSection(&tpinfo->crit);
1529
1530 if (TRACE_ON(olerelay)) {
1531 TRACE_(olerelay)("->");
1532 if (iname)
1533 TRACE_(olerelay)("%s:",relaystr(iname));
1534 if (fname)
1535 TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1536 else
1537 TRACE_(olerelay)("%d",method);
1538 TRACE_(olerelay)("(");
1539 }
1540
1541 SysFreeString(iname);
1542 SysFreeString(fname);
1543
1544 memset(&buf,0,sizeof(buf));
1545
1546 /* normal typelib driven serializing */
1547
1548 /* Need them for hack below */
1549 memset(names,0,sizeof(names));
1550 if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1551 nrofnames = 0;
1552 if (nrofnames > sizeof(names)/sizeof(names[0]))
1553 ERR("Need more names!\n");
1554
1555 xargs = (DWORD_PTR *)(args + 1);
1556 for (i=0;i<fdesc->cParams;i++) {
1557 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1558 if (TRACE_ON(olerelay)) {
1559 if (i) TRACE_(olerelay)(",");
1560 if (i+1<nrofnames && names[i+1])
1561 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1562 }
1563 /* No need to marshal other data than FIN and any VT_PTR. */
1564 if (!is_in_elem(elem))
1565 {
1566 if (elem->tdesc.vt != VT_PTR)
1567 {
1568 xargs+=_argsize(&elem->tdesc, tinfo);
1569 TRACE_(olerelay)("[out]");
1570 continue;
1571 }
1572 else
1573 {
1574 memset( *(void **)xargs, 0, _xsize( elem->tdesc.u.lptdesc, tinfo ) );
1575 }
1576 }
1577
1578 hres = serialize_param(
1579 tinfo,
1580 is_in_elem(elem),
1581 TRACE_ON(olerelay),
1582 FALSE,
1583 &elem->tdesc,
1584 xargs,
1585 &buf
1586 );
1587
1588 if (hres) {
1589 ERR("Failed to serialize param, hres %x\n",hres);
1590 break;
1591 }
1592 xargs+=_argsize(&elem->tdesc, tinfo);
1593 }
1594 TRACE_(olerelay)(")");
1595
1596 memset(&msg,0,sizeof(msg));
1597 msg.cbBuffer = buf.curoff;
1598 msg.iMethod = method;
1599 hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1600 if (hres) {
1601 ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1602 goto exit;
1603 }
1604 memcpy(msg.Buffer,buf.base,buf.curoff);
1605 TRACE_(olerelay)("\n");
1606 hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1607 if (hres) {
1608 ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1609 goto exit;
1610 }
1611
1612 TRACE_(olerelay)(" status = %08x (",status);
1613 if (buf.base)
1614 buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1615 else
1616 buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1617 buf.size = msg.cbBuffer;
1618 memcpy(buf.base,msg.Buffer,buf.size);
1619 buf.curoff = 0;
1620
1621 /* generic deserializer using typelib description */
1622 xargs = (DWORD_PTR *)(args + 1);
1623 status = S_OK;
1624 for (i=0;i<fdesc->cParams;i++) {
1625 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1626
1627 if (i) TRACE_(olerelay)(",");
1628 if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1629
1630 /* No need to marshal other data than FOUT and any VT_PTR */
1631 if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1632 xargs += _argsize(&elem->tdesc, tinfo);
1633 TRACE_(olerelay)("[in]");
1634 continue;
1635 }
1636 hres = deserialize_param(
1637 tinfo,
1638 is_out_elem(elem),
1639 TRACE_ON(olerelay),
1640 FALSE,
1641 &(elem->tdesc),
1642 xargs,
1643 &buf
1644 );
1645 if (hres) {
1646 ERR("Failed to unmarshall param, hres %x\n",hres);
1647 status = hres;
1648 break;
1649 }
1650 xargs += _argsize(&elem->tdesc, tinfo);
1651 }
1652
1653 hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1654 if (hres != S_OK)
1655 goto exit;
1656 TRACE_(olerelay)(") = %08x\n", remoteresult);
1657
1658 hres = remoteresult;
1659
1660 exit:
1661 IRpcChannelBuffer_FreeBuffer(chanbuf,&msg);
1662 for (i = 0; i < nrofnames; i++)
1663 SysFreeString(names[i]);
1664 HeapFree(GetProcessHeap(),0,buf.base);
1665 IRpcChannelBuffer_Release(chanbuf);
1666 ITypeInfo_Release(tinfo);
1667 TRACE("-- 0x%08x\n", hres);
1668 return hres;
1669 }
1670
1671 static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1672 {
1673 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1674
1675 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1676
1677 if (proxy->outerunknown)
1678 return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1679
1680 FIXME("No interface\n");
1681 return E_NOINTERFACE;
1682 }
1683
1684 static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1685 {
1686 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1687
1688 TRACE("\n");
1689
1690 if (proxy->outerunknown)
1691 return IUnknown_AddRef(proxy->outerunknown);
1692
1693 return 2; /* FIXME */
1694 }
1695
1696 static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1697 {
1698 TMProxyImpl *proxy = (TMProxyImpl *)iface;
1699
1700 TRACE("\n");
1701
1702 if (proxy->outerunknown)
1703 return IUnknown_Release(proxy->outerunknown);
1704
1705 return 1; /* FIXME */
1706 }
1707
1708 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1709 {
1710 TMProxyImpl *This = (TMProxyImpl *)iface;
1711
1712 TRACE("(%p)\n", pctinfo);
1713
1714 return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1715 }
1716
1717 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1718 {
1719 TMProxyImpl *This = (TMProxyImpl *)iface;
1720
1721 TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1722
1723 return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1724 }
1725
1726 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1727 {
1728 TMProxyImpl *This = (TMProxyImpl *)iface;
1729
1730 TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1731
1732 return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1733 cNames, lcid, rgDispId);
1734 }
1735
1736 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1737 WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1738 EXCEPINFO * pExcepInfo, UINT * puArgErr)
1739 {
1740 TMProxyImpl *This = (TMProxyImpl *)iface;
1741
1742 TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1743 debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
1744 pExcepInfo, puArgErr);
1745
1746 return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1747 wFlags, pDispParams, pVarResult, pExcepInfo,
1748 puArgErr);
1749 }
1750
1751 typedef struct
1752 {
1753 IRpcChannelBuffer IRpcChannelBuffer_iface;
1754 LONG refs;
1755 /* the IDispatch-derived interface we are handling */
1756 IID tmarshal_iid;
1757 IRpcChannelBuffer *pDelegateChannel;
1758 } TMarshalDispatchChannel;
1759
1760 static inline TMarshalDispatchChannel *impl_from_IRpcChannelBuffer(IRpcChannelBuffer *iface)
1761 {
1762 return CONTAINING_RECORD(iface, TMarshalDispatchChannel, IRpcChannelBuffer_iface);
1763 }
1764
1765 static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(IRpcChannelBuffer *iface, REFIID riid, LPVOID *ppv)
1766 {
1767 *ppv = NULL;
1768 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
1769 {
1770 *ppv = iface;
1771 IRpcChannelBuffer_AddRef(iface);
1772 return S_OK;
1773 }
1774 return E_NOINTERFACE;
1775 }
1776
1777 static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
1778 {
1779 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1780 return InterlockedIncrement(&This->refs);
1781 }
1782
1783 static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
1784 {
1785 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1786 ULONG ref;
1787
1788 ref = InterlockedDecrement(&This->refs);
1789 if (ref)
1790 return ref;
1791
1792 IRpcChannelBuffer_Release(This->pDelegateChannel);
1793 HeapFree(GetProcessHeap(), 0, This);
1794 return 0;
1795 }
1796
1797 static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1798 {
1799 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1800 TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
1801 /* Note: we are pretending to invoke a method on the interface identified
1802 * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
1803 * without the RPC runtime getting confused by not exporting an IDispatch interface */
1804 return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
1805 }
1806
1807 static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1808 {
1809 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1810 TRACE("(%p, %p)\n", olemsg, pstatus);
1811 return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
1812 }
1813
1814 static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1815 {
1816 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1817 TRACE("(%p)\n", olemsg);
1818 return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
1819 }
1820
1821 static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1822 {
1823 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1824 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1825 return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
1826 }
1827
1828 static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
1829 {
1830 TMarshalDispatchChannel *This = impl_from_IRpcChannelBuffer(iface);
1831 TRACE("()\n");
1832 return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
1833 }
1834
1835 static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
1836 {
1837 TMarshalDispatchChannel_QueryInterface,
1838 TMarshalDispatchChannel_AddRef,
1839 TMarshalDispatchChannel_Release,
1840 TMarshalDispatchChannel_GetBuffer,
1841 TMarshalDispatchChannel_SendReceive,
1842 TMarshalDispatchChannel_FreeBuffer,
1843 TMarshalDispatchChannel_GetDestCtx,
1844 TMarshalDispatchChannel_IsConnected
1845 };
1846
1847 static HRESULT TMarshalDispatchChannel_Create(
1848 IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
1849 IRpcChannelBuffer **ppChannel)
1850 {
1851 TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1852 if (!This)
1853 return E_OUTOFMEMORY;
1854
1855 This->IRpcChannelBuffer_iface.lpVtbl = &TMarshalDispatchChannelVtbl;
1856 This->refs = 1;
1857 IRpcChannelBuffer_AddRef(pDelegateChannel);
1858 This->pDelegateChannel = pDelegateChannel;
1859 This->tmarshal_iid = *tmarshal_riid;
1860
1861 *ppChannel = &This->IRpcChannelBuffer_iface;
1862 return S_OK;
1863 }
1864
1865
1866 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
1867 {
1868 HRESULT hr;
1869 CLSID clsid;
1870
1871 if ((hr = CoGetPSClsid(riid, &clsid)))
1872 return hr;
1873 return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
1874 &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1875 }
1876
1877 static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
1878 {
1879 int j;
1880 /* nrofargs including This */
1881 int nrofargs = 1;
1882 ITypeInfo *tinfo2;
1883 TMAsmProxy *xasm = proxy->asmstubs + num;
1884 HRESULT hres;
1885 const FUNCDESC *fdesc;
1886
1887 hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
1888 if (hres) {
1889 ERR("GetFuncDesc %x should not fail here.\n",hres);
1890 return hres;
1891 }
1892 ITypeInfo_Release(tinfo2);
1893 /* some args take more than 4 byte on the stack */
1894 for (j=0;j<fdesc->cParams;j++)
1895 nrofargs += _argsize(&fdesc->lprgelemdescParam[j].tdesc, proxy->tinfo);
1896
1897 #ifdef __i386__
1898 if (fdesc->callconv != CC_STDCALL) {
1899 ERR("calling convention is not stdcall????\n");
1900 return E_FAIL;
1901 }
1902 /* leal 4(%esp),%eax
1903 * pushl %eax
1904 * pushl <nr>
1905 * call xCall
1906 * lret <nr>
1907 */
1908 xasm->lealeax = 0x0424448d;
1909 xasm->pushleax = 0x50;
1910 xasm->pushlval = 0x68;
1911 xasm->nr = num;
1912 xasm->lcall = 0xe8;
1913 xasm->xcall = (char *)xCall - (char *)&xasm->lret;
1914 xasm->lret = 0xc2;
1915 xasm->bytestopop = nrofargs * 4;
1916 xasm->nop = 0x9090;
1917 proxy->lpvtbl[fdesc->oVft / sizeof(void *)] = xasm;
1918
1919 #elif defined(__x86_64__)
1920
1921 xasm->pushq_rbp = 0x55; /* pushq %rbp */
1922 xasm->movq_rsp_rbp[0] = 0x48; /* movq %rsp,%rbp */
1923 xasm->movq_rsp_rbp[1] = 0x89;
1924 xasm->movq_rsp_rbp[2] = 0xe5;
1925 xasm->subq_0x20_rsp = 0x20ec8348; /* subq 0x20,%rsp */
1926 xasm->movq_rcx_0x10rbp = 0x104d8948; /* movq %rcx,0x10(%rbp) */
1927 xasm->movq_rdx_0x18rbp = 0x18558948; /* movq %rdx,0x18(%rbp) */
1928 xasm->movq_r8_0x20rbp = 0x2045894c; /* movq %r8,0x20(%rbp) */
1929 xasm->movq_r9_0x28rbp = 0x284d894c; /* movq %r9,0x28(%rbp) */
1930 xasm->movq_rcx[0] = 0x48; /* movq <num>,%rcx */
1931 xasm->movq_rcx[1] = 0xc7;
1932 xasm->movq_rcx[2] = 0xc1;
1933 xasm->nr = num;
1934 xasm->leaq_0x10rbp_rdx = 0x10558d48; /* leaq 0x10(%rbp),%rdx */
1935 xasm->movq_rax = 0xb848; /* movq <xCall>,%rax */
1936 xasm->xcall = xCall;
1937 xasm->callq_rax = 0xd0ff; /* callq *%rax */
1938 xasm->movq_rbp_rsp[0] = 0x48; /* movq %rbp,%rsp */
1939 xasm->movq_rbp_rsp[1] = 0x89;
1940 xasm->movq_rbp_rsp[2] = 0xec;
1941 xasm->popq_rbp = 0x5d; /* popq %rbp */
1942 xasm->ret = 0xc3; /* ret */
1943 xasm->nop = 0x90909090; /* nop */
1944 proxy->lpvtbl[fdesc->oVft / sizeof(void *)] = xasm;
1945
1946 #else
1947 FIXME("not implemented on non i386\n");
1948 return E_FAIL;
1949 #endif
1950 return S_OK;
1951 }
1952
1953 static HRESULT WINAPI
1954 PSFacBuf_CreateProxy(
1955 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1956 IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1957 {
1958 HRESULT hres;
1959 ITypeInfo *tinfo;
1960 unsigned int i, nroffuncs, vtbl_size;
1961 TMProxyImpl *proxy;
1962 TYPEATTR *typeattr;
1963 BOOL defer_to_dispatch = FALSE;
1964
1965 TRACE("(...%s...)\n",debugstr_guid(riid));
1966 hres = _get_typeinfo_for_iid(riid,&tinfo);
1967 if (hres) {
1968 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1969 return hres;
1970 }
1971
1972 hres = num_of_funcs(tinfo, &nroffuncs, &vtbl_size);
1973 TRACE("Got %d funcs, vtbl size %d\n", nroffuncs, vtbl_size);
1974
1975 if (FAILED(hres)) {
1976 ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
1977 ITypeInfo_Release(tinfo);
1978 return hres;
1979 }
1980
1981 proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1982 if (!proxy) return E_OUTOFMEMORY;
1983
1984 proxy->dispatch = NULL;
1985 proxy->dispatch_proxy = NULL;
1986 proxy->outerunknown = pUnkOuter;
1987 proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1988 if (!proxy->asmstubs) {
1989 ERR("Could not commit pages for proxy thunks\n");
1990 CoTaskMemFree(proxy);
1991 return E_OUTOFMEMORY;
1992 }
1993 proxy->IRpcProxyBuffer_iface.lpVtbl = &tmproxyvtable;
1994 /* one reference for the proxy */
1995 proxy->ref = 1;
1996 proxy->tinfo = tinfo;
1997 proxy->iid = *riid;
1998 proxy->chanbuf = 0;
1999
2000 InitializeCriticalSection(&proxy->crit);
2001 proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
2002
2003 proxy->lpvtbl = HeapAlloc(GetProcessHeap(), 0, vtbl_size);
2004
2005 /* if we derive from IDispatch then defer to its proxy for its methods */
2006 hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2007 if (hres == S_OK)
2008 {
2009 if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2010 {
2011 IPSFactoryBuffer *factory_buffer;
2012 hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
2013 if (hres == S_OK)
2014 {
2015 hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
2016 &IID_IDispatch, &proxy->dispatch_proxy,
2017 (void **)&proxy->dispatch);
2018 IPSFactoryBuffer_Release(factory_buffer);
2019 }
2020 if ((hres == S_OK) && (nroffuncs < 7))
2021 {
2022 ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
2023 hres = E_UNEXPECTED;
2024 }
2025 if (hres == S_OK)
2026 {
2027 defer_to_dispatch = TRUE;
2028 }
2029 }
2030 ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2031 }
2032
2033 for (i=0;i<nroffuncs;i++) {
2034 switch (i) {
2035 case 0:
2036 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
2037 break;
2038 case 1:
2039 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
2040 break;
2041 case 2:
2042 proxy->lpvtbl[i] = ProxyIUnknown_Release;
2043 break;
2044 case 3:
2045 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
2046 else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
2047 break;
2048 case 4:
2049 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
2050 else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
2051 break;
2052 case 5:
2053 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
2054 else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
2055 break;
2056 case 6:
2057 if(!defer_to_dispatch) hres = init_proxy_entry_point(proxy, i);
2058 else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
2059 break;
2060 default:
2061 hres = init_proxy_entry_point(proxy, i);
2062 }
2063 }
2064
2065 if (hres == S_OK)
2066 {
2067 *ppv = proxy;
2068 *ppProxy = &proxy->IRpcProxyBuffer_iface;
2069 IUnknown_AddRef((IUnknown *)*ppv);
2070 return S_OK;
2071 }
2072 else
2073 TMProxyImpl_Release(&proxy->IRpcProxyBuffer_iface);
2074 return hres;
2075 }
2076
2077 typedef struct _TMStubImpl {
2078 IRpcStubBuffer IRpcStubBuffer_iface;
2079 LONG ref;
2080
2081 LPUNKNOWN pUnk;
2082 ITypeInfo *tinfo;
2083 IID iid;
2084 IRpcStubBuffer *dispatch_stub;
2085 BOOL dispatch_derivative;
2086 } TMStubImpl;
2087
2088 static inline TMStubImpl *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
2089 {
2090 return CONTAINING_RECORD(iface, TMStubImpl, IRpcStubBuffer_iface);
2091 }
2092
2093 static HRESULT WINAPI
2094 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
2095 {
2096 if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
2097 *ppv = iface;
2098 IRpcStubBuffer_AddRef(iface);
2099 return S_OK;
2100 }
2101 FIXME("%s, not supported IID.\n",debugstr_guid(riid));
2102 return E_NOINTERFACE;
2103 }
2104
2105 static ULONG WINAPI
2106 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
2107 {
2108 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2109 ULONG refCount = InterlockedIncrement(&This->ref);
2110
2111 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
2112
2113 return refCount;
2114 }
2115
2116 static ULONG WINAPI
2117 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
2118 {
2119 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2120 ULONG refCount = InterlockedDecrement(&This->ref);
2121
2122 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
2123
2124 if (!refCount)
2125 {
2126 IRpcStubBuffer_Disconnect(iface);
2127 ITypeInfo_Release(This->tinfo);
2128 if (This->dispatch_stub)
2129 IRpcStubBuffer_Release(This->dispatch_stub);
2130 CoTaskMemFree(This);
2131 }
2132 return refCount;
2133 }
2134
2135 static HRESULT WINAPI
2136 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
2137 {
2138 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2139
2140 TRACE("(%p)->(%p)\n", This, pUnkServer);
2141
2142 IUnknown_AddRef(pUnkServer);
2143 This->pUnk = pUnkServer;
2144
2145 if (This->dispatch_stub)
2146 IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);
2147
2148 return S_OK;
2149 }
2150
2151 static void WINAPI
2152 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
2153 {
2154 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2155
2156 TRACE("(%p)->()\n", This);
2157
2158 if (This->pUnk)
2159 {
2160 IUnknown_Release(This->pUnk);
2161 This->pUnk = NULL;
2162 }
2163
2164 if (This->dispatch_stub)
2165 IRpcStubBuffer_Disconnect(This->dispatch_stub);
2166 }
2167
2168 static HRESULT WINAPI
2169 TMStubImpl_Invoke(
2170 LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
2171 {
2172 #if defined(__i386__) || defined(__x86_64__)
2173 int i;
2174 const FUNCDESC *fdesc;
2175 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2176 HRESULT hres;
2177 DWORD_PTR *args = NULL, *xargs;
2178 DWORD res, nrofargs;
2179 marshal_state buf;
2180 UINT nrofnames = 0;
2181 BSTR names[10];
2182 BSTR iname = NULL;
2183 ITypeInfo *tinfo = NULL;
2184
2185 TRACE("...\n");
2186
2187 if (xmsg->iMethod < 3) {
2188 ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
2189 return E_UNEXPECTED;
2190 }
2191
2192 if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
2193 {
2194 if (!This->dispatch_stub)
2195 {
2196 IPSFactoryBuffer *factory_buffer;
2197 hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
2198 if (hres == S_OK)
2199 {
2200 hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
2201 This->pUnk, &This->dispatch_stub);
2202 IPSFactoryBuffer_Release(factory_buffer);
2203 }
2204 if (hres != S_OK)
2205 return hres;
2206 }
2207 return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
2208 }
2209
2210 memset(&buf,0,sizeof(buf));
2211 buf.size = xmsg->cbBuffer;
2212 buf.base = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
2213 memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
2214 buf.curoff = 0;
2215
2216 hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
2217 if (hres) {
2218 ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
2219 return hres;
2220 }
2221
2222 if (iname && !lstrcmpW(iname, IDispatchW))
2223 {
2224 ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
2225 hres = E_UNEXPECTED;
2226 SysFreeString (iname);
2227 goto exit;
2228 }
2229
2230 SysFreeString (iname);
2231
2232 /* Need them for hack below */
2233 memset(names,0,sizeof(names));
2234 ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
2235 if (nrofnames > sizeof(names)/sizeof(names[0])) {
2236 ERR("Need more names!\n");
2237 }
2238
2239 /*dump_FUNCDESC(fdesc);*/
2240 nrofargs = 0;
2241 for (i=0;i<fdesc->cParams;i++)
2242 nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo);
2243 args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nrofargs+1)*sizeof(DWORD_PTR));
2244 if (!args)
2245 {
2246 hres = E_OUTOFMEMORY;
2247 goto exit;
2248 }
2249
2250 /* Allocate all stuff used by call. */
2251 xargs = args+1;
2252 for (i=0;i<fdesc->cParams;i++) {
2253 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
2254
2255 hres = deserialize_param(
2256 tinfo,
2257 is_in_elem(elem),
2258 FALSE,
2259 TRUE,
2260 &(elem->tdesc),
2261 xargs,
2262 &buf
2263 );
2264 xargs += _argsize(&elem->tdesc, tinfo);
2265 if (hres) {
2266 ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2267 break;
2268 }
2269 }
2270
2271 args[0] = (DWORD_PTR)This->pUnk;
2272
2273 __TRY
2274 {
2275 res = _invoke(
2276 (*((FARPROC**)args[0]))[fdesc->oVft / sizeof(DWORD_PTR)],
2277 fdesc->callconv,
2278 (xargs-args),
2279 args
2280 );
2281 }
2282 __EXCEPT_ALL
2283 {
2284 DWORD dwExceptionCode = GetExceptionCode();
2285 ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2286 if (FAILED(dwExceptionCode))
2287 hres = dwExceptionCode;
2288 else
2289 hres = HRESULT_FROM_WIN32(dwExceptionCode);
2290 }
2291 __ENDTRY
2292
2293 if (hres != S_OK)
2294 goto exit;
2295
2296 buf.curoff = 0;
2297
2298 xargs = args+1;
2299 for (i=0;i<fdesc->cParams;i++) {
2300 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
2301 hres = serialize_param(
2302 tinfo,
2303 is_out_elem(elem),
2304 FALSE,
2305 TRUE,
2306 &elem->tdesc,
2307 xargs,
2308 &buf
2309 );
2310 xargs += _argsize(&elem->tdesc, tinfo);
2311 if (hres) {
2312 ERR("Failed to stuballoc param, hres %x\n",hres);
2313 break;
2314 }
2315 }
2316
2317 hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2318
2319 if (hres != S_OK)
2320 goto exit;
2321
2322 xmsg->cbBuffer = buf.curoff;
2323 hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
2324 if (hres != S_OK)
2325 ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2326
2327 if (hres == S_OK)
2328 memcpy(xmsg->Buffer, buf.base, buf.curoff);
2329
2330 exit:
2331 for (i = 0; i < nrofnames; i++)
2332 SysFreeString(names[i]);
2333
2334 ITypeInfo_Release(tinfo);
2335 HeapFree(GetProcessHeap(), 0, args);
2336
2337 HeapFree(GetProcessHeap(), 0, buf.base);
2338
2339 TRACE("returning\n");
2340 return hres;
2341 #else
2342 FIXME( "not implemented on non-i386\n" );
2343 return E_FAIL;
2344 #endif
2345 }
2346
2347 static LPRPCSTUBBUFFER WINAPI
2348 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
2349 FIXME("Huh (%s)?\n",debugstr_guid(riid));
2350 return NULL;
2351 }
2352
2353 static ULONG WINAPI
2354 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
2355 TMStubImpl *This = impl_from_IRpcStubBuffer(iface);
2356
2357 FIXME("()\n");
2358 return This->ref; /*FIXME? */
2359 }
2360
2361 static HRESULT WINAPI
2362 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
2363 return E_NOTIMPL;
2364 }
2365
2366 static void WINAPI
2367 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
2368 return;
2369 }
2370
2371 static const IRpcStubBufferVtbl tmstubvtbl = {
2372 TMStubImpl_QueryInterface,
2373 TMStubImpl_AddRef,
2374 TMStubImpl_Release,
2375 TMStubImpl_Connect,
2376 TMStubImpl_Disconnect,
2377 TMStubImpl_Invoke,
2378 TMStubImpl_IsIIDSupported,
2379 TMStubImpl_CountRefs,
2380 TMStubImpl_DebugServerQueryInterface,
2381 TMStubImpl_DebugServerRelease
2382 };
2383
2384 static HRESULT WINAPI
2385 PSFacBuf_CreateStub(
2386 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
2387 IRpcStubBuffer** ppStub
2388 ) {
2389 HRESULT hres;
2390 ITypeInfo *tinfo;
2391 TMStubImpl *stub;
2392 TYPEATTR *typeattr;
2393 IUnknown *obj;
2394
2395 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2396
2397 hres = _get_typeinfo_for_iid(riid,&tinfo);
2398 if (hres) {
2399 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2400 return hres;
2401 }
2402
2403 /* FIXME: This is not exactly right. We should probably call QI later. */
2404 hres = IUnknown_QueryInterface(pUnkServer, riid, (void**)&obj);
2405 if (FAILED(hres)) {
2406 WARN("Could not get %s iface: %08x\n", debugstr_guid(riid), hres);
2407 obj = pUnkServer;
2408 IUnknown_AddRef(obj);
2409 }
2410
2411 stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2412 if (!stub) {
2413 IUnknown_Release(obj);
2414 return E_OUTOFMEMORY;
2415 }
2416 stub->IRpcStubBuffer_iface.lpVtbl = &tmstubvtbl;
2417 stub->ref = 1;
2418 stub->tinfo = tinfo;
2419 stub->dispatch_stub = NULL;
2420 stub->dispatch_derivative = FALSE;
2421 stub->iid = *riid;
2422 hres = IRpcStubBuffer_Connect(&stub->IRpcStubBuffer_iface, obj);
2423 *ppStub = &stub->IRpcStubBuffer_iface;
2424 TRACE("IRpcStubBuffer: %p\n", stub);
2425 if (hres)
2426 ERR("Connect to pUnkServer failed?\n");
2427
2428 /* if we derive from IDispatch then defer to its stub for some of its methods */
2429 hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2430 if (hres == S_OK)
2431 {
2432 if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2433 stub->dispatch_derivative = TRUE;
2434 ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2435 }
2436
2437 IUnknown_Release(obj);
2438 return hres;
2439 }
2440
2441 static const IPSFactoryBufferVtbl psfacbufvtbl = {
2442 PSFacBuf_QueryInterface,
2443 PSFacBuf_AddRef,
2444 PSFacBuf_Release,
2445 PSFacBuf_CreateProxy,
2446 PSFacBuf_CreateStub
2447 };
2448
2449 static IPSFactoryBuffer psfac = { &psfacbufvtbl };
2450
2451 /***********************************************************************
2452 * TMARSHAL_DllGetClassObject
2453 */
2454 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid, void **ppv)
2455 {
2456 return IPSFactoryBuffer_QueryInterface(&psfac, iid, ppv);
2457 }