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