Sync to Wine-20050211
[reactos.git] / reactos / lib / oleaut32 / tmarshal.c
1 /*
2 * TYPELIB Marshaler
3 *
4 * Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "config.h"
25
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <ctype.h>
32
33 #define COBJMACROS
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36
37 #include "winerror.h"
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winnls.h"
41 #include "winreg.h"
42 #include "winuser.h"
43
44 #include "ole2.h"
45 #include "typelib.h"
46 #include "wine/debug.h"
47
48 static const WCHAR riidW[5] = {'r','i','i','d',0};
49 static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};
50 static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};
51
52 WINE_DEFAULT_DEBUG_CHANNEL(ole);
53 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
54
55 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
56
57 typedef struct _marshal_state {
58 LPBYTE base;
59 int size;
60 int curoff;
61
62 BOOL thisisiid;
63 IID iid; /* HACK: for VT_VOID */
64 } marshal_state;
65
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;
72 }
73
74 static HRESULT
75 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
76 while (buf->size - buf->curoff < size) {
77 if (buf->base) {
78 buf->size += 100;
79 buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
80 if (!buf->base)
81 return E_OUTOFMEMORY;
82 } else {
83 buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
84 buf->size = 32;
85 if (!buf->base)
86 return E_OUTOFMEMORY;
87 }
88 }
89 memcpy(buf->base+buf->curoff,stuff,size);
90 buf->curoff += size;
91 return S_OK;
92 }
93
94 static HRESULT
95 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
96 if (buf->size < buf->curoff+size) return E_FAIL;
97 memcpy(stuff,buf->base+buf->curoff,size);
98 buf->curoff += size;
99 return S_OK;
100 }
101
102 static HRESULT
103 xbuf_skip(marshal_state *buf, DWORD size) {
104 if (buf->size < buf->curoff+size) return E_FAIL;
105 buf->curoff += size;
106 return S_OK;
107 }
108
109 static HRESULT
110 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
111 IStream *pStm;
112 ULARGE_INTEGER newpos;
113 LARGE_INTEGER seekto;
114 ULONG res;
115 HRESULT hres;
116 DWORD xsize;
117
118 TRACE("...%s...\n",debugstr_guid(riid));
119
120 *pUnk = NULL;
121 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
122 if (hres) {
123 ERR("xbuf_get failed\n");
124 return hres;
125 }
126
127 if (xsize == 0) return S_OK;
128
129 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
130 if (hres) {
131 ERR("Stream create failed %lx\n",hres);
132 return hres;
133 }
134
135 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
136 if (hres) {
137 ERR("stream write %lx\n",hres);
138 return hres;
139 }
140
141 memset(&seekto,0,sizeof(seekto));
142 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
143 if (hres) {
144 ERR("Failed Seek %lx\n",hres);
145 return hres;
146 }
147
148 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
149 if (hres) {
150 ERR("Unmarshalling interface %s failed with %lx\n",debugstr_guid(riid),hres);
151 return hres;
152 }
153
154 IStream_Release(pStm);
155 return xbuf_skip(buf,xsize);
156 }
157
158 static HRESULT
159 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
160 LPUNKNOWN newiface = NULL;
161 LPBYTE tempbuf = NULL;
162 IStream *pStm = NULL;
163 STATSTG ststg;
164 ULARGE_INTEGER newpos;
165 LARGE_INTEGER seekto;
166 ULONG res;
167 DWORD xsize;
168 HRESULT hres;
169
170 hres = E_FAIL;
171 if (!pUnk) {
172 ERR("pUnk is NULL?\n");
173 goto fail;
174 }
175
176 TRACE("...%s...\n",debugstr_guid(riid));
177 hres = IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
178 if (hres) {
179 WARN("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
180 goto fail;
181 }
182
183 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
184 if (hres) {
185 ERR("Stream create failed %lx\n",hres);
186 goto fail;
187 }
188
189 hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
190 if (hres) {
191 ERR("Marshalling interface %s failed with %lx\n", debugstr_guid(riid), hres);
192 goto fail;
193 }
194
195 hres = IStream_Stat(pStm,&ststg,0);
196 if (hres) {
197 ERR("Stream stat failed\n");
198 goto fail;
199 }
200
201 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
202 memset(&seekto,0,sizeof(seekto));
203 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
204 if (hres) {
205 ERR("Failed Seek %lx\n",hres);
206 goto fail;
207 }
208
209 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
210 if (hres) {
211 ERR("Failed Read %lx\n",hres);
212 goto fail;
213 }
214
215 xsize = ststg.cbSize.u.LowPart;
216 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
217 hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
218
219 HeapFree(GetProcessHeap(),0,tempbuf);
220 IUnknown_Release(newiface);
221 IStream_Release(pStm);
222
223 return hres;
224
225 fail:
226 xsize = 0;
227 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
228 if (pStm) IUnknown_Release(pStm);
229 if (newiface) IUnknown_Release(newiface);
230 HeapFree(GetProcessHeap(), 0, tempbuf);
231 return hres;
232 }
233
234 /********************* OLE Proxy/Stub Factory ********************************/
235 static HRESULT WINAPI
236 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
237 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
238 *ppv = (LPVOID)iface;
239 /* No ref counting, static class */
240 return S_OK;
241 }
242 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
243 return E_NOINTERFACE;
244 }
245
246 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
247 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
248
249 static HRESULT
250 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
251 HRESULT hres;
252 HKEY ikey;
253 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
254 char tlfn[260];
255 OLECHAR tlfnW[260];
256 DWORD tlguidlen, verlen, type, tlfnlen;
257 ITypeLib *tl;
258
259 sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
260 riid->Data1, riid->Data2, riid->Data3,
261 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
262 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
263 );
264
265 if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
266 ERR("No %s key found.\n",interfacekey);
267 return E_FAIL;
268 }
269 type = (1<<REG_SZ);
270 tlguidlen = sizeof(tlguid);
271 if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
272 ERR("Getting typelib guid failed.\n");
273 RegCloseKey(ikey);
274 return E_FAIL;
275 }
276 type = (1<<REG_SZ);
277 verlen = sizeof(ver);
278 if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
279 ERR("Could not get version value?\n");
280 RegCloseKey(ikey);
281 return E_FAIL;
282 }
283 RegCloseKey(ikey);
284 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
285 tlfnlen = sizeof(tlfn);
286 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
287 ERR("Could not get typelib fn?\n");
288 return E_FAIL;
289 }
290 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
291 hres = LoadTypeLib(tlfnW,&tl);
292 if (hres) {
293 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
294 return hres;
295 }
296 hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
297 if (hres) {
298 ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
299 ITypeLib_Release(tl);
300 return hres;
301 }
302 /* FIXME: do this? ITypeLib_Release(tl); */
303 return hres;
304 }
305
306 /* Determine nr of functions. Since we use the toplevel interface and all
307 * inherited ones have lower numbers, we are ok to not to descent into
308 * the inheritance tree I think.
309 */
310 static int _nroffuncs(ITypeInfo *tinfo) {
311 int n, max = 0;
312 FUNCDESC *fdesc;
313 HRESULT hres;
314
315 n=0;
316 while (1) {
317 hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
318 if (hres)
319 return max+1;
320 if (fdesc->oVft/4 > max)
321 max = fdesc->oVft/4;
322 n++;
323 }
324 /*NOTREACHED*/
325 }
326
327 #ifdef __i386__
328
329 #include "pshpack1.h"
330
331 typedef struct _TMAsmProxy {
332 BYTE popleax;
333 BYTE pushlval;
334 BYTE nr;
335 BYTE pushleax;
336 BYTE lcall;
337 DWORD xcall;
338 BYTE lret;
339 WORD bytestopop;
340 } TMAsmProxy;
341
342 #include "poppack.h"
343
344 #else /* __i386__ */
345 # error You need to implement stubless proxies for your architecture
346 #endif
347
348 typedef struct _TMProxyImpl {
349 LPVOID *lpvtbl;
350 IRpcProxyBufferVtbl *lpvtbl2;
351 ULONG ref;
352
353 TMAsmProxy *asmstubs;
354 ITypeInfo* tinfo;
355 IRpcChannelBuffer* chanbuf;
356 IID iid;
357 CRITICAL_SECTION crit;
358 } TMProxyImpl;
359
360 static HRESULT WINAPI
361 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
362 {
363 TRACE("()\n");
364 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
365 *ppv = (LPVOID)iface;
366 IRpcProxyBuffer_AddRef(iface);
367 return S_OK;
368 }
369 FIXME("no interface for %s\n",debugstr_guid(riid));
370 return E_NOINTERFACE;
371 }
372
373 static ULONG WINAPI
374 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
375 {
376 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
377 ULONG refCount = InterlockedIncrement(&This->ref);
378
379 TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);
380
381 return refCount;
382 }
383
384 static ULONG WINAPI
385 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
386 {
387 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
388 ULONG refCount = InterlockedDecrement(&This->ref);
389
390 TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1);
391
392 if (!refCount)
393 {
394 DeleteCriticalSection(&This->crit);
395 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
396 VirtualFree(This->asmstubs, 0, MEM_RELEASE);
397 CoTaskMemFree(This);
398 }
399 return refCount;
400 }
401
402 static HRESULT WINAPI
403 TMProxyImpl_Connect(
404 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
405 {
406 ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
407
408 TRACE("(%p)\n", pRpcChannelBuffer);
409
410 EnterCriticalSection(&This->crit);
411
412 IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
413 This->chanbuf = pRpcChannelBuffer;
414
415 LeaveCriticalSection(&This->crit);
416
417 return S_OK;
418 }
419
420 static void WINAPI
421 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
422 {
423 ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
424
425 TRACE("()\n");
426
427 EnterCriticalSection(&This->crit);
428
429 IRpcChannelBuffer_Release(This->chanbuf);
430 This->chanbuf = NULL;
431
432 LeaveCriticalSection(&This->crit);
433 }
434
435
436 static IRpcProxyBufferVtbl tmproxyvtable = {
437 TMProxyImpl_QueryInterface,
438 TMProxyImpl_AddRef,
439 TMProxyImpl_Release,
440 TMProxyImpl_Connect,
441 TMProxyImpl_Disconnect
442 };
443
444 /* how much space do we use on stack in DWORD steps. */
445 int
446 _argsize(DWORD vt) {
447 switch (vt) {
448 case VT_DATE:
449 return sizeof(DATE)/sizeof(DWORD);
450 case VT_VARIANT:
451 return (sizeof(VARIANT)+3)/sizeof(DWORD);
452 default:
453 return 1;
454 }
455 }
456
457 static int
458 _xsize(TYPEDESC *td) {
459 switch (td->vt) {
460 case VT_DATE:
461 return sizeof(DATE);
462 case VT_VARIANT:
463 return sizeof(VARIANT)+3;
464 case VT_CARRAY: {
465 int i, arrsize = 1;
466 ARRAYDESC *adesc = td->u.lpadesc;
467
468 for (i=0;i<adesc->cDims;i++)
469 arrsize *= adesc->rgbounds[i].cElements;
470 return arrsize*_xsize(&adesc->tdescElem);
471 }
472 case VT_UI2:
473 case VT_I2:
474 return 2;
475 case VT_UI1:
476 case VT_I1:
477 return 1;
478 default:
479 return 4;
480 }
481 }
482
483 static HRESULT
484 serialize_param(
485 ITypeInfo *tinfo,
486 BOOL writeit,
487 BOOL debugout,
488 BOOL dealloc,
489 TYPEDESC *tdesc,
490 DWORD *arg,
491 marshal_state *buf)
492 {
493 HRESULT hres = S_OK;
494
495 TRACE("(tdesc.vt %d)\n",tdesc->vt);
496
497 switch (tdesc->vt) {
498 case VT_EMPTY: /* nothing. empty variant for instance */
499 return S_OK;
500 case VT_BOOL:
501 case VT_ERROR:
502 case VT_UI4:
503 case VT_UINT:
504 case VT_I4:
505 case VT_R4:
506 case VT_UI2:
507 case VT_UI1:
508 hres = S_OK;
509 if (debugout) TRACE_(olerelay)("%lx",*arg);
510 if (writeit)
511 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
512 return hres;
513 case VT_VARIANT: {
514 TYPEDESC tdesc2;
515 VARIANT *vt = (VARIANT*)arg;
516 DWORD vttype = V_VT(vt);
517
518 if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
519 tdesc2.vt = vttype;
520 if (writeit) {
521 hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
522 if (hres) return hres;
523 }
524 /* need to recurse since we need to free the stuff */
525 hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);
526 if (debugout) TRACE_(olerelay)(")");
527 return hres;
528 }
529 case VT_BSTR: {
530 if (debugout) {
531 if (arg)
532 TRACE_(olerelay)("%s",relaystr((BSTR)*arg));
533 else
534 TRACE_(olerelay)("<bstr NULL>");
535 }
536 if (writeit) {
537 if (!*arg) {
538 DWORD fakelen = -1;
539 hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
540 if (hres)
541 return hres;
542 } else {
543 DWORD *bstr = ((DWORD*)(*arg))-1;
544
545 hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
546 if (hres)
547 return hres;
548 }
549 }
550
551 if (dealloc && arg)
552 SysFreeString((BSTR)*arg);
553 return S_OK;
554 }
555 case VT_PTR: {
556 DWORD cookie;
557
558 if (debugout) TRACE_(olerelay)("*");
559 if (writeit) {
560 cookie = *arg ? 0x42424242 : 0;
561 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
562 if (hres)
563 return hres;
564 }
565 if (!*arg) {
566 if (debugout) TRACE_(olerelay)("NULL");
567 return S_OK;
568 }
569 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
570 if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
571 return hres;
572 }
573 case VT_UNKNOWN:
574 if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg);
575 if (writeit)
576 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
577 return hres;
578 case VT_DISPATCH:
579 if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg);
580 if (writeit)
581 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
582 return hres;
583 case VT_VOID:
584 if (debugout) TRACE_(olerelay)("<void>");
585 return S_OK;
586 case VT_USERDEFINED: {
587 ITypeInfo *tinfo2;
588 TYPEATTR *tattr;
589
590 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
591 if (hres) {
592 ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
593 return hres;
594 }
595 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
596 switch (tattr->typekind) {
597 case TKIND_DISPATCH:
598 case TKIND_INTERFACE:
599 if (writeit)
600 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
601 break;
602 case TKIND_RECORD: {
603 int i;
604 if (debugout) TRACE_(olerelay)("{");
605 for (i=0;i<tattr->cVars;i++) {
606 VARDESC *vdesc;
607 ELEMDESC *elem2;
608 TYPEDESC *tdesc2;
609
610 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
611 if (hres) {
612 ERR("Could not get vardesc of %d\n",i);
613 return hres;
614 }
615 /* Need them for hack below */
616 /*
617 memset(names,0,sizeof(names));
618 hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
619 if (nrofnames > sizeof(names)/sizeof(names[0])) {
620 ERR("Need more names!\n");
621 }
622 if (!hres && debugout)
623 TRACE_(olerelay)("%s=",relaystr(names[0]));
624 */
625 elem2 = &vdesc->elemdescVar;
626 tdesc2 = &elem2->tdesc;
627 hres = serialize_param(
628 tinfo2,
629 writeit,
630 debugout,
631 dealloc,
632 tdesc2,
633 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
634 buf
635 );
636 if (hres!=S_OK)
637 return hres;
638 if (debugout && (i<(tattr->cVars-1)))
639 TRACE_(olerelay)(",");
640 }
641 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
642 memcpy(&(buf->iid),arg,sizeof(buf->iid));
643 if (debugout) TRACE_(olerelay)("}");
644 break;
645 }
646 default:
647 FIXME("Unhandled typekind %d\n",tattr->typekind);
648 hres = E_FAIL;
649 break;
650 }
651 ITypeInfo_Release(tinfo2);
652 return hres;
653 }
654 case VT_CARRAY: {
655 ARRAYDESC *adesc = tdesc->u.lpadesc;
656 int i, arrsize = 1;
657
658 if (debugout) TRACE_(olerelay)("carr");
659 for (i=0;i<adesc->cDims;i++) {
660 if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);
661 arrsize *= adesc->rgbounds[i].cElements;
662 }
663 if (debugout) TRACE_(olerelay)("[");
664 for (i=0;i<arrsize;i++) {
665 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
666 if (hres)
667 return hres;
668 if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
669 }
670 if (debugout) TRACE_(olerelay)("]");
671 return S_OK;
672 }
673 default:
674 ERR("Unhandled marshal type %d.\n",tdesc->vt);
675 return S_OK;
676 }
677 }
678
679 static HRESULT
680 serialize_LPVOID_ptr(
681 ITypeInfo *tinfo,
682 BOOL writeit,
683 BOOL debugout,
684 BOOL dealloc,
685 TYPEDESC *tdesc,
686 DWORD *arg,
687 marshal_state *buf)
688 {
689 HRESULT hres;
690 DWORD cookie;
691
692 if ((tdesc->vt != VT_PTR) ||
693 (tdesc->u.lptdesc->vt != VT_PTR) ||
694 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
695 ) {
696 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
697 return E_FAIL;
698 }
699 cookie = (*arg) ? 0x42424242: 0x0;
700 if (writeit) {
701 hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
702 if (hres)
703 return hres;
704 }
705 if (!*arg) {
706 if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
707 return S_OK;
708 }
709 if (debugout)
710 TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg);
711 if (writeit) {
712 hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
713 if (hres)
714 return hres;
715 }
716 if (dealloc)
717 HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
718 return S_OK;
719 }
720
721 static HRESULT
722 serialize_DISPPARAM_ptr(
723 ITypeInfo *tinfo,
724 BOOL writeit,
725 BOOL debugout,
726 BOOL dealloc,
727 TYPEDESC *tdesc,
728 DWORD *arg,
729 marshal_state *buf)
730 {
731 DWORD cookie;
732 HRESULT hres;
733 DISPPARAMS *disp;
734 int i;
735
736 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
737 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
738 return E_FAIL;
739 }
740
741 cookie = *arg ? 0x42424242 : 0x0;
742 if (writeit) {
743 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
744 if (hres)
745 return hres;
746 }
747 if (!*arg) {
748 if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
749 return S_OK;
750 }
751 disp = (DISPPARAMS*)*arg;
752 if (writeit) {
753 hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
754 if (hres)
755 return hres;
756 }
757 if (debugout) TRACE_(olerelay)("D{");
758 for (i=0;i<disp->cArgs;i++) {
759 TYPEDESC vtdesc;
760
761 vtdesc.vt = VT_VARIANT;
762 serialize_param(
763 tinfo,
764 writeit,
765 debugout,
766 dealloc,
767 &vtdesc,
768 (DWORD*)(disp->rgvarg+i),
769 buf
770 );
771 if (debugout && (i<disp->cArgs-1))
772 TRACE_(olerelay)(",");
773 }
774 if (dealloc)
775 HeapFree(GetProcessHeap(),0,disp->rgvarg);
776 if (writeit) {
777 hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
778 if (hres)
779 return hres;
780 }
781 if (debugout) TRACE_(olerelay)("}{");
782 for (i=0;i<disp->cNamedArgs;i++) {
783 TYPEDESC vtdesc;
784
785 vtdesc.vt = VT_UINT;
786 serialize_param(
787 tinfo,
788 writeit,
789 debugout,
790 dealloc,
791 &vtdesc,
792 (DWORD*)(disp->rgdispidNamedArgs+i),
793 buf
794 );
795 if (debugout && (i<disp->cNamedArgs-1))
796 TRACE_(olerelay)(",");
797 }
798 if (debugout) TRACE_(olerelay)("}");
799 if (dealloc) {
800 HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
801 HeapFree(GetProcessHeap(),0,disp);
802 }
803 return S_OK;
804 }
805
806 static HRESULT
807 deserialize_param(
808 ITypeInfo *tinfo,
809 BOOL readit,
810 BOOL debugout,
811 BOOL alloc,
812 TYPEDESC *tdesc,
813 DWORD *arg,
814 marshal_state *buf)
815 {
816 HRESULT hres = S_OK;
817
818 TRACE("vt %d at %p\n",tdesc->vt,arg);
819
820 while (1) {
821 switch (tdesc->vt) {
822 case VT_EMPTY:
823 if (debugout) TRACE_(olerelay)("<empty>");
824 return S_OK;
825 case VT_NULL:
826 if (debugout) TRACE_(olerelay)("<null>");
827 return S_OK;
828 case VT_VARIANT: {
829 VARIANT *vt = (VARIANT*)arg;
830
831 if (readit) {
832 DWORD vttype;
833 TYPEDESC tdesc2;
834 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
835 if (hres) {
836 FIXME("vt type not read?\n");
837 return hres;
838 }
839 memset(&tdesc2,0,sizeof(tdesc2));
840 tdesc2.vt = vttype;
841 V_VT(vt) = vttype;
842 if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
843 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);
844 TRACE_(olerelay)(")");
845 return hres;
846 } else {
847 VariantInit(vt);
848 return S_OK;
849 }
850 }
851 case VT_ERROR:
852 case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT: case VT_R4:
853 case VT_UI2:
854 case VT_UI1:
855 if (readit) {
856 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
857 if (hres) ERR("Failed to read integer 4 byte\n");
858 }
859 if (debugout) TRACE_(olerelay)("%lx",*arg);
860 return hres;
861 case VT_BSTR: {
862 WCHAR *str;
863 DWORD len;
864
865 if (readit) {
866 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
867 if (hres) {
868 ERR("failed to read bstr klen\n");
869 return hres;
870 }
871 if (len == -1) {
872 *arg = 0;
873 if (debugout) TRACE_(olerelay)("<bstr NULL>");
874 } else {
875 str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
876 hres = xbuf_get(buf,(LPBYTE)str,len);
877 if (hres) {
878 ERR("Failed to read BSTR.\n");
879 return hres;
880 }
881 *arg = (DWORD)SysAllocStringLen(str,len);
882 if (debugout) TRACE_(olerelay)("%s",relaystr(str));
883 HeapFree(GetProcessHeap(),0,str);
884 }
885 } else {
886 *arg = 0;
887 }
888 return S_OK;
889 }
890 case VT_PTR: {
891 DWORD cookie;
892 BOOL derefhere = 0;
893
894 derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
895
896 if (readit) {
897 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
898 if (hres) {
899 ERR("Failed to load pointer cookie.\n");
900 return hres;
901 }
902 if (cookie != 0x42424242) {
903 if (debugout) TRACE_(olerelay)("NULL");
904 *arg = 0;
905 return S_OK;
906 }
907 if (debugout) TRACE_(olerelay)("*");
908 }
909 if (alloc) {
910 if (derefhere)
911 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
912 }
913 if (derefhere)
914 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
915 else
916 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
917 }
918 case VT_UNKNOWN:
919 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
920 if (alloc)
921 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
922 hres = S_OK;
923 if (readit)
924 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
925 if (debugout)
926 TRACE_(olerelay)("unk(%p)",arg);
927 return hres;
928 case VT_DISPATCH:
929 hres = S_OK;
930 if (readit)
931 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
932 if (debugout)
933 TRACE_(olerelay)("idisp(%p)",arg);
934 return hres;
935 case VT_VOID:
936 if (debugout) TRACE_(olerelay)("<void>");
937 return S_OK;
938 case VT_USERDEFINED: {
939 ITypeInfo *tinfo2;
940 TYPEATTR *tattr;
941
942 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
943 if (hres) {
944 ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
945 return hres;
946 }
947 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
948 if (hres) {
949 ERR("Could not get typeattr in VT_USERDEFINED.\n");
950 } else {
951 if (alloc)
952 *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
953 switch (tattr->typekind) {
954 case TKIND_DISPATCH:
955 case TKIND_INTERFACE:
956 if (readit)
957 hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
958 break;
959 case TKIND_RECORD: {
960 int i;
961
962 if (debugout) TRACE_(olerelay)("{");
963 for (i=0;i<tattr->cVars;i++) {
964 VARDESC *vdesc;
965
966 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
967 if (hres) {
968 ERR("Could not get vardesc of %d\n",i);
969 return hres;
970 }
971 hres = deserialize_param(
972 tinfo2,
973 readit,
974 debugout,
975 alloc,
976 &vdesc->elemdescVar.tdesc,
977 (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
978 buf
979 );
980 if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
981 }
982 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
983 memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
984 if (debugout) TRACE_(olerelay)("}");
985 break;
986 }
987 default:
988 ERR("Unhandled typekind %d\n",tattr->typekind);
989 hres = E_FAIL;
990 break;
991 }
992 }
993 if (hres)
994 ERR("failed to stuballoc in TKIND_RECORD.\n");
995 ITypeInfo_Release(tinfo2);
996 return hres;
997 }
998 case VT_CARRAY: {
999 /* arg is pointing to the start of the array. */
1000 ARRAYDESC *adesc = tdesc->u.lpadesc;
1001 int arrsize,i;
1002 arrsize = 1;
1003 if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1004 for (i=0;i<adesc->cDims;i++)
1005 arrsize *= adesc->rgbounds[i].cElements;
1006 for (i=0;i<arrsize;i++)
1007 deserialize_param(
1008 tinfo,
1009 readit,
1010 debugout,
1011 alloc,
1012 &adesc->tdescElem,
1013 (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),
1014 buf
1015 );
1016 return S_OK;
1017 }
1018 default:
1019 ERR("No handler for VT type %d!\n",tdesc->vt);
1020 return S_OK;
1021 }
1022 }
1023 }
1024
1025 static HRESULT
1026 deserialize_LPVOID_ptr(
1027 ITypeInfo *tinfo,
1028 BOOL readit,
1029 BOOL debugout,
1030 BOOL alloc,
1031 TYPEDESC *tdesc,
1032 DWORD *arg,
1033 marshal_state *buf
1034 ) {
1035 HRESULT hres;
1036 DWORD cookie;
1037
1038 if ((tdesc->vt != VT_PTR) ||
1039 (tdesc->u.lptdesc->vt != VT_PTR) ||
1040 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
1041 ) {
1042 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
1043 return E_FAIL;
1044 }
1045 if (alloc)
1046 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
1047 if (readit) {
1048 hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));
1049 if (hres)
1050 return hres;
1051 if (cookie != 0x42424242) {
1052 *(DWORD*)*arg = 0;
1053 if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
1054 return S_OK;
1055 }
1056 }
1057 if (readit) {
1058 hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);
1059 if (hres)
1060 return hres;
1061 }
1062 if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg);
1063 return S_OK;
1064 }
1065
1066 static HRESULT
1067 deserialize_DISPPARAM_ptr(
1068 ITypeInfo *tinfo,
1069 BOOL readit,
1070 BOOL debugout,
1071 BOOL alloc,
1072 TYPEDESC *tdesc,
1073 DWORD *arg,
1074 marshal_state *buf)
1075 {
1076 DWORD cookie;
1077 DISPPARAMS *disps;
1078 HRESULT hres;
1079 int i;
1080
1081 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
1082 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
1083 return E_FAIL;
1084 }
1085 if (readit) {
1086 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1087 if (hres)
1088 return hres;
1089 if (cookie == 0) {
1090 *arg = 0;
1091 if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
1092 return S_OK;
1093 }
1094 }
1095 if (alloc)
1096 *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));
1097 disps = (DISPPARAMS*)*arg;
1098 if (!readit)
1099 return S_OK;
1100 hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));
1101 if (hres)
1102 return hres;
1103 if (alloc)
1104 disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);
1105 if (debugout) TRACE_(olerelay)("D{");
1106 for (i=0; i< disps->cArgs; i++) {
1107 TYPEDESC vdesc;
1108
1109 vdesc.vt = VT_VARIANT;
1110 hres = deserialize_param(
1111 tinfo,
1112 readit,
1113 debugout,
1114 alloc,
1115 &vdesc,
1116 (DWORD*)(disps->rgvarg+i),
1117 buf
1118 );
1119 }
1120 if (debugout) TRACE_(olerelay)("}{");
1121 hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));
1122 if (hres)
1123 return hres;
1124 if (disps->cNamedArgs) {
1125 if (alloc)
1126 disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);
1127 for (i=0; i< disps->cNamedArgs; i++) {
1128 TYPEDESC vdesc;
1129
1130 vdesc.vt = VT_UINT;
1131 hres = deserialize_param(
1132 tinfo,
1133 readit,
1134 debugout,
1135 alloc,
1136 &vdesc,
1137 (DWORD*)(disps->rgdispidNamedArgs+i),
1138 buf
1139 );
1140 if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(",");
1141 }
1142 }
1143 if (debugout) TRACE_(olerelay)("}");
1144 return S_OK;
1145 }
1146
1147 /* Searches function, also in inherited interfaces */
1148 static HRESULT
1149 _get_funcdesc(
1150 ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname)
1151 {
1152 int i = 0, j = 0;
1153 HRESULT hres;
1154
1155 if (fname) *fname = NULL;
1156 if (iname) *iname = NULL;
1157
1158 while (1) {
1159 hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
1160 if (hres) {
1161 ITypeInfo *tinfo2;
1162 HREFTYPE href;
1163 TYPEATTR *attr;
1164
1165 hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
1166 if (hres) {
1167 ERR("GetTypeAttr failed with %lx\n",hres);
1168 return hres;
1169 }
1170 /* Not found, so look in inherited ifaces. */
1171 for (j=0;j<attr->cImplTypes;j++) {
1172 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
1173 if (hres) {
1174 ERR("Did not find a reftype for interface offset %d?\n",j);
1175 break;
1176 }
1177 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1178 if (hres) {
1179 ERR("Did not find a typeinfo for reftype %ld?\n",href);
1180 continue;
1181 }
1182 hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
1183 ITypeInfo_Release(tinfo2);
1184 if (!hres) return S_OK;
1185 }
1186 return hres;
1187 }
1188 if (((*fdesc)->oVft/4) == iMethod) {
1189 if (fname)
1190 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1191 if (iname)
1192 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1193 return S_OK;
1194 }
1195 i++;
1196 }
1197 }
1198
1199 static DWORD
1200 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1201 {
1202 DWORD *args = ((DWORD*)&tpinfo)+1, *xargs;
1203 FUNCDESC *fdesc;
1204 HRESULT hres;
1205 int i, relaydeb = TRACE_ON(olerelay);
1206 marshal_state buf;
1207 RPCOLEMESSAGE msg;
1208 ULONG status;
1209 BSTR fname,iname;
1210 BSTR names[10];
1211 int nrofnames;
1212
1213 EnterCriticalSection(&tpinfo->crit);
1214
1215 hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
1216 if (hres) {
1217 ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1218 LeaveCriticalSection(&tpinfo->crit);
1219 return E_FAIL;
1220 }
1221
1222 if (!tpinfo->chanbuf)
1223 {
1224 WARN("Tried to use disconnected proxy\n");
1225 LeaveCriticalSection(&tpinfo->crit);
1226 return RPC_E_DISCONNECTED;
1227 }
1228
1229 if (relaydeb) {
1230 TRACE_(olerelay)("->");
1231 if (iname)
1232 TRACE_(olerelay)("%s:",relaystr(iname));
1233 if (fname)
1234 TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1235 else
1236 TRACE_(olerelay)("%d",method);
1237 TRACE_(olerelay)("(");
1238 if (iname) SysFreeString(iname);
1239 if (fname) SysFreeString(fname);
1240 }
1241 /* Need them for hack below */
1242 memset(names,0,sizeof(names));
1243 if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1244 nrofnames = 0;
1245 if (nrofnames > sizeof(names)/sizeof(names[0]))
1246 ERR("Need more names!\n");
1247
1248 memset(&buf,0,sizeof(buf));
1249 buf.iid = IID_IUnknown;
1250 if (method == 0) {
1251 xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
1252 if (relaydeb) TRACE_(olerelay)("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
1253 } else {
1254 xargs = args;
1255 for (i=0;i<fdesc->cParams;i++) {
1256 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1257 BOOL isserialized = FALSE;
1258 if (relaydeb) {
1259 if (i) TRACE_(olerelay)(",");
1260 if (i+1<nrofnames && names[i+1])
1261 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1262 }
1263 /* No need to marshal other data than FIN */
1264 if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
1265 xargs+=_argsize(elem->tdesc.vt);
1266 if (relaydeb) TRACE_(olerelay)("[out]");
1267 continue;
1268 }
1269 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1270 /* If the parameter is 'riid', we use it as interface IID
1271 * for a later ppvObject serialization.
1272 */
1273 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1274
1275 /* DISPPARAMS* needs special serializer */
1276 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1277 hres = serialize_DISPPARAM_ptr(
1278 tpinfo->tinfo,
1279 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1280 relaydeb,
1281 FALSE,
1282 &elem->tdesc,
1283 xargs,
1284 &buf
1285 );
1286 isserialized = TRUE;
1287 }
1288 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1289 hres = serialize_LPVOID_ptr(
1290 tpinfo->tinfo,
1291 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1292 relaydeb,
1293 FALSE,
1294 &elem->tdesc,
1295 xargs,
1296 &buf
1297 );
1298 if (hres == S_OK)
1299 isserialized = TRUE;
1300 }
1301 }
1302 if (!isserialized)
1303 hres = serialize_param(
1304 tpinfo->tinfo,
1305 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1306 relaydeb,
1307 FALSE,
1308 &elem->tdesc,
1309 xargs,
1310 &buf
1311 );
1312
1313 if (hres) {
1314 ERR("Failed to serialize param, hres %lx\n",hres);
1315 break;
1316 }
1317 xargs+=_argsize(elem->tdesc.vt);
1318 }
1319 }
1320 if (relaydeb) TRACE_(olerelay)(")");
1321 memset(&msg,0,sizeof(msg));
1322 msg.cbBuffer = buf.curoff;
1323 msg.iMethod = method;
1324 hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
1325 if (hres) {
1326 ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
1327 LeaveCriticalSection(&tpinfo->crit);
1328 return hres;
1329 }
1330 memcpy(msg.Buffer,buf.base,buf.curoff);
1331 if (relaydeb) TRACE_(olerelay)("\n");
1332 hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
1333 if (hres) {
1334 ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);
1335 LeaveCriticalSection(&tpinfo->crit);
1336 return hres;
1337 }
1338
1339 if (relaydeb) TRACE_(olerelay)(" = %08lx (",status);
1340 if (buf.base)
1341 buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1342 else
1343 buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1344 buf.size = msg.cbBuffer;
1345 memcpy(buf.base,msg.Buffer,buf.size);
1346 buf.curoff = 0;
1347 if (method == 0) {
1348 _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
1349 if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1]));
1350 } else {
1351 xargs = args;
1352 for (i=0;i<fdesc->cParams;i++) {
1353 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1354 BOOL isdeserialized = FALSE;
1355
1356 if (relaydeb) {
1357 if (i) TRACE_(olerelay)(",");
1358 if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1359 }
1360 /* No need to marshal other data than FOUT I think */
1361 if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
1362 xargs += _argsize(elem->tdesc.vt);
1363 if (relaydeb) TRACE_(olerelay)("[in]");
1364 continue;
1365 }
1366 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1367 /* If the parameter is 'riid', we use it as interface IID
1368 * for a later ppvObject serialization.
1369 */
1370 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1371
1372 /* deserialize DISPPARAM */
1373 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1374 hres = deserialize_DISPPARAM_ptr(
1375 tpinfo->tinfo,
1376 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1377 relaydeb,
1378 FALSE,
1379 &(elem->tdesc),
1380 xargs,
1381 &buf
1382 );
1383 if (hres) {
1384 ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1385 break;
1386 }
1387 isdeserialized = TRUE;
1388 }
1389 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1390 hres = deserialize_LPVOID_ptr(
1391 tpinfo->tinfo,
1392 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1393 relaydeb,
1394 FALSE,
1395 &elem->tdesc,
1396 xargs,
1397 &buf
1398 );
1399 if (hres == S_OK)
1400 isdeserialized = TRUE;
1401 }
1402 }
1403 if (!isdeserialized)
1404 hres = deserialize_param(
1405 tpinfo->tinfo,
1406 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1407 relaydeb,
1408 FALSE,
1409 &(elem->tdesc),
1410 xargs,
1411 &buf
1412 );
1413 if (hres) {
1414 ERR("Failed to unmarshall param, hres %lx\n",hres);
1415 status = hres;
1416 break;
1417 }
1418 xargs += _argsize(elem->tdesc.vt);
1419 }
1420 }
1421 if (relaydeb) TRACE_(olerelay)(")\n");
1422 HeapFree(GetProcessHeap(),0,buf.base);
1423
1424 LeaveCriticalSection(&tpinfo->crit);
1425
1426 return status;
1427 }
1428
1429 static HRESULT WINAPI
1430 PSFacBuf_CreateProxy(
1431 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1432 IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1433 {
1434 HRESULT hres;
1435 ITypeInfo *tinfo;
1436 int i, nroffuncs;
1437 FUNCDESC *fdesc;
1438 TMProxyImpl *proxy;
1439
1440 TRACE("(...%s...)\n",debugstr_guid(riid));
1441 hres = _get_typeinfo_for_iid(riid,&tinfo);
1442 if (hres) {
1443 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1444 return hres;
1445 }
1446 nroffuncs = _nroffuncs(tinfo);
1447 proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1448 if (!proxy) return E_OUTOFMEMORY;
1449
1450 assert(sizeof(TMAsmProxy) == 12);
1451
1452 proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1453 if (!proxy->asmstubs) {
1454 ERR("Could not commit pages for proxy thunks\n");
1455 CoTaskMemFree(proxy);
1456 return E_OUTOFMEMORY;
1457 }
1458
1459 InitializeCriticalSection(&proxy->crit);
1460
1461 proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1462 for (i=0;i<nroffuncs;i++) {
1463 int nrofargs;
1464 TMAsmProxy *xasm = proxy->asmstubs+i;
1465
1466 /* nrofargs without This */
1467 switch (i) {
1468 case 0: nrofargs = 2;
1469 break;
1470 case 1: case 2: nrofargs = 0;
1471 break;
1472 default: {
1473 int j;
1474 hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
1475 if (hres) {
1476 ERR("GetFuncDesc %lx should not fail here.\n",hres);
1477 return hres;
1478 }
1479 /* some args take more than 4 byte on the stack */
1480 nrofargs = 0;
1481 for (j=0;j<fdesc->cParams;j++)
1482 nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
1483
1484 if (fdesc->callconv != CC_STDCALL) {
1485 ERR("calling convention is not stdcall????\n");
1486 return E_FAIL;
1487 }
1488 break;
1489 }
1490 }
1491 /* popl %eax - return ptr
1492 * pushl <nr>
1493 * pushl %eax
1494 * call xCall
1495 * lret <nr> (+4)
1496 *
1497 *
1498 * arg3 arg2 arg1 <method> <returnptr>
1499 */
1500 xasm->popleax = 0x58;
1501 xasm->pushlval = 0x6a;
1502 xasm->nr = i;
1503 xasm->pushleax = 0x50;
1504 xasm->lcall = 0xe8; /* relative jump */
1505 xasm->xcall = (DWORD)xCall;
1506 xasm->xcall -= (DWORD)&(xasm->lret);
1507 xasm->lret = 0xc2;
1508 xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
1509 proxy->lpvtbl[i] = xasm;
1510 }
1511 proxy->lpvtbl2 = &tmproxyvtable;
1512 /* 1 reference for the proxy and 1 for the object */
1513 proxy->ref = 2;
1514 proxy->tinfo = tinfo;
1515 memcpy(&proxy->iid,riid,sizeof(*riid));
1516 proxy->chanbuf = 0;
1517 *ppv = (LPVOID)proxy;
1518 *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1519 return S_OK;
1520 }
1521
1522 typedef struct _TMStubImpl {
1523 IRpcStubBufferVtbl *lpvtbl;
1524 ULONG ref;
1525
1526 LPUNKNOWN pUnk;
1527 ITypeInfo *tinfo;
1528 IID iid;
1529 } TMStubImpl;
1530
1531 static HRESULT WINAPI
1532 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1533 {
1534 if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1535 *ppv = (LPVOID)iface;
1536 IRpcStubBuffer_AddRef(iface);
1537 return S_OK;
1538 }
1539 FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1540 return E_NOINTERFACE;
1541 }
1542
1543 static ULONG WINAPI
1544 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1545 {
1546 TMStubImpl *This = (TMStubImpl *)iface;
1547 ULONG refCount = InterlockedIncrement(&This->ref);
1548
1549 TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
1550
1551 return refCount;
1552 }
1553
1554 static ULONG WINAPI
1555 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1556 {
1557 TMStubImpl *This = (TMStubImpl *)iface;
1558 ULONG refCount = InterlockedDecrement(&This->ref);
1559
1560 TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
1561
1562 if (!refCount)
1563 {
1564 IRpcStubBuffer_Disconnect(iface);
1565 CoTaskMemFree(This);
1566 }
1567 return refCount;
1568 }
1569
1570 static HRESULT WINAPI
1571 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1572 {
1573 TMStubImpl *This = (TMStubImpl *)iface;
1574
1575 TRACE("(%p)->(%p)\n", This, pUnkServer);
1576
1577 IUnknown_AddRef(pUnkServer);
1578 This->pUnk = pUnkServer;
1579 return S_OK;
1580 }
1581
1582 static void WINAPI
1583 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1584 {
1585 TMStubImpl *This = (TMStubImpl *)iface;
1586
1587 TRACE("(%p)->()\n", This);
1588
1589 IUnknown_Release(This->pUnk);
1590 This->pUnk = NULL;
1591 return;
1592 }
1593
1594 static HRESULT WINAPI
1595 TMStubImpl_Invoke(
1596 LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1597 {
1598 int i;
1599 FUNCDESC *fdesc;
1600 TMStubImpl *This = (TMStubImpl *)iface;
1601 HRESULT hres;
1602 DWORD *args, res, *xargs, nrofargs;
1603 marshal_state buf;
1604 int nrofnames;
1605 BSTR names[10];
1606
1607 memset(&buf,0,sizeof(buf));
1608 buf.size = xmsg->cbBuffer;
1609 buf.base = xmsg->Buffer;
1610 buf.curoff = 0;
1611 buf.iid = IID_IUnknown;
1612
1613 TRACE("...\n");
1614 if (xmsg->iMethod == 0) { /* QI */
1615 IID xiid;
1616 /* in: IID, out: <iface> */
1617
1618 xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
1619 buf.curoff = 0;
1620 hres = _marshal_interface(&buf,&xiid,This->pUnk);
1621 xmsg->Buffer = buf.base; /* Might have been reallocated */
1622 xmsg->cbBuffer = buf.size;
1623 return hres;
1624 }
1625 hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
1626 if (hres) {
1627 ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1628 return hres;
1629 }
1630 /* Need them for hack below */
1631 memset(names,0,sizeof(names));
1632 ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1633 if (nrofnames > sizeof(names)/sizeof(names[0])) {
1634 ERR("Need more names!\n");
1635 }
1636
1637 /*dump_FUNCDESC(fdesc);*/
1638 nrofargs = 0;
1639 for (i=0;i<fdesc->cParams;i++)
1640 nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1641 args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1642 if (!args) return E_OUTOFMEMORY;
1643
1644 /* Allocate all stuff used by call. */
1645 xargs = args+1;
1646 for (i=0;i<fdesc->cParams;i++) {
1647 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1648 BOOL isdeserialized = FALSE;
1649
1650 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1651 /* If the parameter is 'riid', we use it as interface IID
1652 * for a later ppvObject serialization.
1653 */
1654 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1655
1656 /* deserialize DISPPARAM */
1657 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1658 hres = deserialize_DISPPARAM_ptr(
1659 This->tinfo,
1660 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1661 FALSE,
1662 TRUE,
1663 &(elem->tdesc),
1664 xargs,
1665 &buf
1666 );
1667 if (hres) {
1668 ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1669 break;
1670 }
1671 isdeserialized = TRUE;
1672 }
1673 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1674 hres = deserialize_LPVOID_ptr(
1675 This->tinfo,
1676 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1677 FALSE,
1678 TRUE,
1679 &elem->tdesc,
1680 xargs,
1681 &buf
1682 );
1683 if (hres == S_OK)
1684 isdeserialized = TRUE;
1685 }
1686 }
1687 if (!isdeserialized)
1688 hres = deserialize_param(
1689 This->tinfo,
1690 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1691 FALSE,
1692 TRUE,
1693 &(elem->tdesc),
1694 xargs,
1695 &buf
1696 );
1697 xargs += _argsize(elem->tdesc.vt);
1698 if (hres) {
1699 ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
1700 break;
1701 }
1702 }
1703 hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1704 if (hres) {
1705 ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
1706 return hres;
1707 }
1708 res = _invoke(
1709 (*((FARPROC**)args[0]))[fdesc->oVft/4],
1710 fdesc->callconv,
1711 (xargs-args),
1712 args
1713 );
1714 IUnknown_Release((LPUNKNOWN)args[0]);
1715 buf.curoff = 0;
1716 xargs = args+1;
1717 for (i=0;i<fdesc->cParams;i++) {
1718 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1719 BOOL isserialized = FALSE;
1720
1721 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1722 /* If the parameter is 'riid', we use it as interface IID
1723 * for a later ppvObject serialization.
1724 */
1725 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1726
1727 /* DISPPARAMS* needs special serializer */
1728 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1729 hres = serialize_DISPPARAM_ptr(
1730 This->tinfo,
1731 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1732 FALSE,
1733 TRUE,
1734 &elem->tdesc,
1735 xargs,
1736 &buf
1737 );
1738 isserialized = TRUE;
1739 }
1740 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1741 hres = serialize_LPVOID_ptr(
1742 This->tinfo,
1743 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1744 FALSE,
1745 TRUE,
1746 &elem->tdesc,
1747 xargs,
1748 &buf
1749 );
1750 if (hres == S_OK)
1751 isserialized = TRUE;
1752 }
1753 }
1754 if (!isserialized)
1755 hres = serialize_param(
1756 This->tinfo,
1757 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1758 FALSE,
1759 TRUE,
1760 &elem->tdesc,
1761 xargs,
1762 &buf
1763 );
1764 xargs += _argsize(elem->tdesc.vt);
1765 if (hres) {
1766 ERR("Failed to stuballoc param, hres %lx\n",hres);
1767 break;
1768 }
1769 }
1770 /* might need to use IRpcChannelBuffer_GetBuffer ? */
1771 xmsg->cbBuffer = buf.curoff;
1772 xmsg->Buffer = buf.base;
1773 HeapFree(GetProcessHeap(),0,args);
1774 return res;
1775 }
1776
1777 static LPRPCSTUBBUFFER WINAPI
1778 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1779 FIXME("Huh (%s)?\n",debugstr_guid(riid));
1780 return NULL;
1781 }
1782
1783 static ULONG WINAPI
1784 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1785 TMStubImpl *This = (TMStubImpl *)iface;
1786
1787 return This->ref; /*FIXME? */
1788 }
1789
1790 static HRESULT WINAPI
1791 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1792 return E_NOTIMPL;
1793 }
1794
1795 static void WINAPI
1796 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1797 return;
1798 }
1799
1800 IRpcStubBufferVtbl tmstubvtbl = {
1801 TMStubImpl_QueryInterface,
1802 TMStubImpl_AddRef,
1803 TMStubImpl_Release,
1804 TMStubImpl_Connect,
1805 TMStubImpl_Disconnect,
1806 TMStubImpl_Invoke,
1807 TMStubImpl_IsIIDSupported,
1808 TMStubImpl_CountRefs,
1809 TMStubImpl_DebugServerQueryInterface,
1810 TMStubImpl_DebugServerRelease
1811 };
1812
1813 static HRESULT WINAPI
1814 PSFacBuf_CreateStub(
1815 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1816 IRpcStubBuffer** ppStub
1817 ) {
1818 HRESULT hres;
1819 ITypeInfo *tinfo;
1820 TMStubImpl *stub;
1821
1822 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1823 hres = _get_typeinfo_for_iid(riid,&tinfo);
1824 if (hres) {
1825 ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1826 return hres;
1827 }
1828 stub = CoTaskMemAlloc(sizeof(TMStubImpl));
1829 if (!stub)
1830 return E_OUTOFMEMORY;
1831 stub->lpvtbl = &tmstubvtbl;
1832 stub->ref = 1;
1833 stub->tinfo = tinfo;
1834 memcpy(&(stub->iid),riid,sizeof(*riid));
1835 hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1836 *ppStub = (LPRPCSTUBBUFFER)stub;
1837 TRACE("IRpcStubBuffer: %p\n", stub);
1838 if (hres)
1839 ERR("Connect to pUnkServer failed?\n");
1840 return hres;
1841 }
1842
1843 static IPSFactoryBufferVtbl psfacbufvtbl = {
1844 PSFacBuf_QueryInterface,
1845 PSFacBuf_AddRef,
1846 PSFacBuf_Release,
1847 PSFacBuf_CreateProxy,
1848 PSFacBuf_CreateStub
1849 };
1850
1851 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1852 static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
1853
1854 /***********************************************************************
1855 * DllGetClassObject [OLE32.63]
1856 */
1857 HRESULT WINAPI
1858 TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1859 {
1860 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1861 *ppv = &lppsfac;
1862 return S_OK;
1863 }
1864 return E_NOINTERFACE;
1865 }