Function return types cannot be const.
[wine.git] / dlls / oleaut32 / tmarshal.c
bloba70ea63437913f28d9ede1743f29f29d21e8e237
1 /*
2 * TYPELIB Marshaler
4 * Copyright 2002 Marcus Meissner
6 * The olerelay debug channel allows you to see calls marshalled by
7 * the typelib marshaller. It is not a generic COM relaying system.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <ctype.h>
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winnls.h"
39 #include "winreg.h"
40 #include "winuser.h"
42 #include "ole2.h"
43 #include "wine/unicode.h"
44 #include "ole2disp.h"
45 #include "typelib.h"
46 #include "wine/debug.h"
47 #include "winternl.h"
49 static const WCHAR riidW[5] = {'r','i','i','d',0};
50 static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};
51 static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
56 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
58 typedef struct _marshal_state {
59 LPBYTE base;
60 int size;
61 int curoff;
63 BOOL thisisiid;
64 IID iid; /* HACK: for VT_VOID */
65 } marshal_state;
67 /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
68 static char *relaystr(WCHAR *in) {
69 char *tmp = (char *)debugstr_w(in);
70 tmp += 2;
71 tmp[strlen(tmp)-1] = '\0';
72 return tmp;
75 static HRESULT
76 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
77 while (buf->size - buf->curoff < size) {
78 if (buf->base) {
79 buf->size += 100;
80 buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
81 if (!buf->base)
82 return E_OUTOFMEMORY;
83 } else {
84 buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
85 buf->size = 32;
86 if (!buf->base)
87 return E_OUTOFMEMORY;
90 memcpy(buf->base+buf->curoff,stuff,size);
91 buf->curoff += size;
92 return S_OK;
95 static HRESULT
96 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
97 if (buf->size < buf->curoff+size) return E_FAIL;
98 memcpy(stuff,buf->base+buf->curoff,size);
99 buf->curoff += size;
100 return S_OK;
103 static HRESULT
104 xbuf_skip(marshal_state *buf, DWORD size) {
105 if (buf->size < buf->curoff+size) return E_FAIL;
106 buf->curoff += size;
107 return S_OK;
110 static HRESULT
111 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
112 IStream *pStm;
113 ULARGE_INTEGER newpos;
114 LARGE_INTEGER seekto;
115 ULONG res;
116 HRESULT hres;
117 DWORD xsize;
119 TRACE("...%s...\n",debugstr_guid(riid));
120 *pUnk = NULL;
121 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
122 if (hres) return hres;
123 if (xsize == 0) return S_OK;
124 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
125 if (hres) {
126 FIXME("Stream create failed %lx\n",hres);
127 return hres;
129 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
130 if (hres) { FIXME("stream write %lx\n",hres); return hres; }
131 memset(&seekto,0,sizeof(seekto));
132 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
133 if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;}
134 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
135 if (hres) {
136 FIXME("Marshalling interface %s failed with %lx\n",debugstr_guid(riid),hres);
137 return hres;
139 IStream_Release(pStm);
140 return xbuf_skip(buf,xsize);
143 static HRESULT
144 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
145 LPUNKNOWN newiface;
146 LPBYTE tempbuf;
147 IStream *pStm;
148 STATSTG ststg;
149 ULARGE_INTEGER newpos;
150 LARGE_INTEGER seekto;
151 ULONG res;
152 DWORD xsize;
153 HRESULT hres;
155 hres = S_OK;
156 if (!pUnk)
157 goto fail;
159 TRACE("...%s...\n",debugstr_guid(riid));
160 hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
161 if (hres) {
162 TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
163 goto fail;
165 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
166 if (hres) {
167 FIXME("Stream create failed %lx\n",hres);
168 goto fail;
170 hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
171 IUnknown_Release(newiface);
172 if (hres) {
173 FIXME("Marshalling interface %s failed with %lx\n",
174 debugstr_guid(riid),hres
176 goto fail;
178 hres = IStream_Stat(pStm,&ststg,0);
179 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
180 memset(&seekto,0,sizeof(seekto));
181 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
182 if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;}
183 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
184 if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;}
185 IStream_Release(pStm);
186 xsize = ststg.cbSize.u.LowPart;
187 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
188 hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
189 HeapFree(GetProcessHeap(),0,tempbuf);
190 return hres;
191 fail:
192 xsize = 0;
193 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
194 return hres;
197 /********************* OLE Proxy/Stub Factory ********************************/
198 static HRESULT WINAPI
199 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
200 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
201 *ppv = (LPVOID)iface;
202 /* No ref counting, static class */
203 return S_OK;
205 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
206 return E_NOINTERFACE;
209 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
210 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
212 static HRESULT
213 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
214 HRESULT hres;
215 HKEY ikey;
216 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
217 char tlfn[260];
218 OLECHAR tlfnW[260];
219 DWORD tlguidlen, verlen, type, tlfnlen;
220 ITypeLib *tl;
222 sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
223 riid->Data1, riid->Data2, riid->Data3,
224 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
225 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
228 if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
229 FIXME("No %s key found.\n",interfacekey);
230 return E_FAIL;
232 type = (1<<REG_SZ);
233 tlguidlen = sizeof(tlguid);
234 if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
235 FIXME("Getting typelib guid failed.\n");
236 RegCloseKey(ikey);
237 return E_FAIL;
239 type = (1<<REG_SZ);
240 verlen = sizeof(ver);
241 if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
242 FIXME("Could not get version value?\n");
243 RegCloseKey(ikey);
244 return E_FAIL;
246 RegCloseKey(ikey);
247 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
248 tlfnlen = sizeof(tlfn);
249 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
250 FIXME("Could not get typelib fn?\n");
251 return E_FAIL;
253 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
254 hres = LoadTypeLib(tlfnW,&tl);
255 if (hres) {
256 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
257 return hres;
259 hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
260 if (hres) {
261 ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
262 ITypeLib_Release(tl);
263 return hres;
265 /* FIXME: do this? ITypeLib_Release(tl); */
266 return hres;
269 /* Determine nr of functions. Since we use the toplevel interface and all
270 * inherited ones have lower numbers, we are ok to not to descent into
271 * the inheritance tree I think.
273 static int _nroffuncs(ITypeInfo *tinfo) {
274 int n, max = 0;
275 FUNCDESC *fdesc;
276 HRESULT hres;
278 n=0;
279 while (1) {
280 hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
281 if (hres)
282 return max+1;
283 if (fdesc->oVft/4 > max)
284 max = fdesc->oVft/4;
285 n++;
287 /*NOTREACHED*/
290 #ifdef __i386__
292 #include "pshpack1.h"
294 typedef struct _TMAsmProxy {
295 BYTE popleax;
296 BYTE pushlval;
297 BYTE nr;
298 BYTE pushleax;
299 BYTE lcall;
300 DWORD xcall;
301 BYTE lret;
302 WORD bytestopop;
303 } TMAsmProxy;
305 #include "poppack.h"
307 #else /* __i386__ */
308 # error You need to implement stubless proxies for your architecture
309 #endif
311 typedef struct _TMProxyImpl {
312 LPVOID *lpvtbl;
313 IRpcProxyBufferVtbl *lpvtbl2;
314 ULONG ref;
316 TMAsmProxy *asmstubs;
317 ITypeInfo* tinfo;
318 IRpcChannelBuffer* chanbuf;
319 IID iid;
320 CRITICAL_SECTION crit;
321 } TMProxyImpl;
323 static HRESULT WINAPI
324 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
326 TRACE("()\n");
327 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
328 *ppv = (LPVOID)iface;
329 IRpcProxyBuffer_AddRef(iface);
330 return S_OK;
332 FIXME("no interface for %s\n",debugstr_guid(riid));
333 return E_NOINTERFACE;
336 static ULONG WINAPI
337 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
339 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
341 TRACE("()\n");
343 return InterlockedIncrement(&This->ref);
346 static ULONG WINAPI
347 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
349 ULONG refs;
350 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
352 TRACE("()\n");
354 refs = InterlockedDecrement(&This->ref);
355 if (!refs)
357 DeleteCriticalSection(&This->crit);
358 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
359 VirtualFree(This->asmstubs, 0, MEM_RELEASE);
360 CoTaskMemFree(This);
362 return refs;
365 static HRESULT WINAPI
366 TMProxyImpl_Connect(
367 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
369 ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
371 TRACE("(%p)\n", pRpcChannelBuffer);
373 EnterCriticalSection(&This->crit);
375 IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
376 This->chanbuf = pRpcChannelBuffer;
378 LeaveCriticalSection(&This->crit);
380 return S_OK;
383 static void WINAPI
384 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
386 ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
388 TRACE("()\n");
390 EnterCriticalSection(&This->crit);
392 IRpcChannelBuffer_Release(This->chanbuf);
393 This->chanbuf = NULL;
395 LeaveCriticalSection(&This->crit);
399 static IRpcProxyBufferVtbl tmproxyvtable = {
400 TMProxyImpl_QueryInterface,
401 TMProxyImpl_AddRef,
402 TMProxyImpl_Release,
403 TMProxyImpl_Connect,
404 TMProxyImpl_Disconnect
407 /* how much space do we use on stack in DWORD steps. */
409 _argsize(DWORD vt) {
410 switch (vt) {
411 case VT_DATE:
412 return sizeof(DATE)/sizeof(DWORD);
413 case VT_VARIANT:
414 return (sizeof(VARIANT)+3)/sizeof(DWORD);
415 default:
416 return 1;
420 static int
421 _xsize(TYPEDESC *td) {
422 switch (td->vt) {
423 case VT_DATE:
424 return sizeof(DATE);
425 case VT_VARIANT:
426 return sizeof(VARIANT)+3;
427 case VT_CARRAY: {
428 int i, arrsize = 1;
429 ARRAYDESC *adesc = td->u.lpadesc;
431 for (i=0;i<adesc->cDims;i++)
432 arrsize *= adesc->rgbounds[i].cElements;
433 return arrsize*_xsize(&adesc->tdescElem);
435 case VT_UI2:
436 case VT_I2:
437 return 2;
438 case VT_UI1:
439 case VT_I1:
440 return 1;
441 default:
442 return 4;
446 static HRESULT
447 serialize_param(
448 ITypeInfo *tinfo,
449 BOOL writeit,
450 BOOL debugout,
451 BOOL dealloc,
452 TYPEDESC *tdesc,
453 DWORD *arg,
454 marshal_state *buf)
456 HRESULT hres = S_OK;
458 TRACE("(tdesc.vt %d)\n",tdesc->vt);
460 switch (tdesc->vt) {
461 case VT_EMPTY: /* nothing. empty variant for instance */
462 return S_OK;
463 case VT_BOOL:
464 case VT_ERROR:
465 case VT_UI4:
466 case VT_UINT:
467 case VT_I4:
468 case VT_R4:
469 case VT_UI2:
470 case VT_UI1:
471 hres = S_OK;
472 if (debugout) TRACE_(olerelay)("%lx",*arg);
473 if (writeit)
474 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
475 return hres;
476 case VT_VARIANT: {
477 TYPEDESC tdesc2;
478 VARIANT *vt = (VARIANT*)arg;
479 DWORD vttype = V_VT(vt);
481 if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
482 tdesc2.vt = vttype;
483 if (writeit) {
484 hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
485 if (hres) return hres;
487 /* need to recurse since we need to free the stuff */
488 hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);
489 if (debugout) TRACE_(olerelay)(")");
490 return hres;
492 case VT_BSTR: {
493 if (debugout) {
494 if (arg)
495 TRACE_(olerelay)("%s",relaystr((BSTR)*arg));
496 else
497 TRACE_(olerelay)("<bstr NULL>");
499 if (writeit) {
500 if (!*arg) {
501 DWORD fakelen = -1;
502 hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
503 if (hres)
504 return hres;
505 } else {
506 DWORD *bstr = ((DWORD*)(*arg))-1;
508 hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
509 if (hres)
510 return hres;
514 if (dealloc && arg)
515 SysFreeString((BSTR)*arg);
516 return S_OK;
518 case VT_PTR: {
519 DWORD cookie;
521 if (debugout) TRACE_(olerelay)("*");
522 if (writeit) {
523 cookie = *arg ? 0x42424242 : 0;
524 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
525 if (hres)
526 return hres;
528 if (!*arg) {
529 if (debugout) TRACE_(olerelay)("NULL");
530 return S_OK;
532 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
533 if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
534 return hres;
536 case VT_UNKNOWN:
537 if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg);
538 if (writeit)
539 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
540 return hres;
541 case VT_DISPATCH:
542 if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg);
543 if (writeit)
544 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
545 return hres;
546 case VT_VOID:
547 if (debugout) TRACE_(olerelay)("<void>");
548 return S_OK;
549 case VT_USERDEFINED: {
550 ITypeInfo *tinfo2;
551 TYPEATTR *tattr;
553 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
554 if (hres) {
555 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
556 return hres;
558 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
559 switch (tattr->typekind) {
560 case TKIND_DISPATCH:
561 case TKIND_INTERFACE:
562 if (writeit)
563 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
564 break;
565 case TKIND_RECORD: {
566 int i;
567 if (debugout) TRACE_(olerelay)("{");
568 for (i=0;i<tattr->cVars;i++) {
569 VARDESC *vdesc;
570 ELEMDESC *elem2;
571 TYPEDESC *tdesc2;
573 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
574 if (hres) {
575 FIXME("Could not get vardesc of %d\n",i);
576 return hres;
578 /* Need them for hack below */
580 memset(names,0,sizeof(names));
581 hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
582 if (nrofnames > sizeof(names)/sizeof(names[0])) {
583 ERR("Need more names!\n");
585 if (!hres && debugout)
586 TRACE_(olerelay)("%s=",relaystr(names[0]));
588 elem2 = &vdesc->elemdescVar;
589 tdesc2 = &elem2->tdesc;
590 hres = serialize_param(
591 tinfo2,
592 writeit,
593 debugout,
594 dealloc,
595 tdesc2,
596 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
599 if (hres!=S_OK)
600 return hres;
601 if (debugout && (i<(tattr->cVars-1)))
602 TRACE_(olerelay)(",");
604 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
605 memcpy(&(buf->iid),arg,sizeof(buf->iid));
606 if (debugout) TRACE_(olerelay)("}");
607 break;
609 default:
610 FIXME("Unhandled typekind %d\n",tattr->typekind);
611 hres = E_FAIL;
612 break;
614 ITypeInfo_Release(tinfo2);
615 return hres;
617 case VT_CARRAY: {
618 ARRAYDESC *adesc = tdesc->u.lpadesc;
619 int i, arrsize = 1;
621 if (debugout) TRACE_(olerelay)("carr");
622 for (i=0;i<adesc->cDims;i++) {
623 if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);
624 arrsize *= adesc->rgbounds[i].cElements;
626 if (debugout) TRACE_(olerelay)("[");
627 for (i=0;i<arrsize;i++) {
628 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
629 if (hres)
630 return hres;
631 if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
633 if (debugout) TRACE_(olerelay)("]");
634 return S_OK;
636 default:
637 ERR("Unhandled marshal type %d.\n",tdesc->vt);
638 return S_OK;
642 static HRESULT
643 serialize_LPVOID_ptr(
644 ITypeInfo *tinfo,
645 BOOL writeit,
646 BOOL debugout,
647 BOOL dealloc,
648 TYPEDESC *tdesc,
649 DWORD *arg,
650 marshal_state *buf)
652 HRESULT hres;
653 DWORD cookie;
655 if ((tdesc->vt != VT_PTR) ||
656 (tdesc->u.lptdesc->vt != VT_PTR) ||
657 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
659 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
660 return E_FAIL;
662 cookie = (*arg) ? 0x42424242: 0x0;
663 if (writeit) {
664 hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
665 if (hres)
666 return hres;
668 if (!*arg) {
669 if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
670 return S_OK;
672 if (debugout)
673 TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg);
674 if (writeit) {
675 hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
676 if (hres)
677 return hres;
679 if (dealloc)
680 HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
681 return S_OK;
684 static HRESULT
685 serialize_DISPPARAM_ptr(
686 ITypeInfo *tinfo,
687 BOOL writeit,
688 BOOL debugout,
689 BOOL dealloc,
690 TYPEDESC *tdesc,
691 DWORD *arg,
692 marshal_state *buf)
694 DWORD cookie;
695 HRESULT hres;
696 DISPPARAMS *disp;
697 int i;
699 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
700 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
701 return E_FAIL;
704 cookie = *arg ? 0x42424242 : 0x0;
705 if (writeit) {
706 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
707 if (hres)
708 return hres;
710 if (!*arg) {
711 if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
712 return S_OK;
714 disp = (DISPPARAMS*)*arg;
715 if (writeit) {
716 hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
717 if (hres)
718 return hres;
720 if (debugout) TRACE_(olerelay)("D{");
721 for (i=0;i<disp->cArgs;i++) {
722 TYPEDESC vtdesc;
724 vtdesc.vt = VT_VARIANT;
725 serialize_param(
726 tinfo,
727 writeit,
728 debugout,
729 dealloc,
730 &vtdesc,
731 (DWORD*)(disp->rgvarg+i),
734 if (debugout && (i<disp->cArgs-1))
735 TRACE_(olerelay)(",");
737 if (dealloc)
738 HeapFree(GetProcessHeap(),0,disp->rgvarg);
739 if (writeit) {
740 hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
741 if (hres)
742 return hres;
744 if (debugout) TRACE_(olerelay)("}{");
745 for (i=0;i<disp->cNamedArgs;i++) {
746 TYPEDESC vtdesc;
748 vtdesc.vt = VT_UINT;
749 serialize_param(
750 tinfo,
751 writeit,
752 debugout,
753 dealloc,
754 &vtdesc,
755 (DWORD*)(disp->rgdispidNamedArgs+i),
758 if (debugout && (i<disp->cNamedArgs-1))
759 TRACE_(olerelay)(",");
761 if (debugout) TRACE_(olerelay)("}");
762 if (dealloc) {
763 HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
764 HeapFree(GetProcessHeap(),0,disp);
766 return S_OK;
769 static HRESULT
770 deserialize_param(
771 ITypeInfo *tinfo,
772 BOOL readit,
773 BOOL debugout,
774 BOOL alloc,
775 TYPEDESC *tdesc,
776 DWORD *arg,
777 marshal_state *buf)
779 HRESULT hres = S_OK;
781 TRACE("vt %d at %p\n",tdesc->vt,arg);
783 while (1) {
784 switch (tdesc->vt) {
785 case VT_EMPTY:
786 if (debugout) TRACE_(olerelay)("<empty>");
787 return S_OK;
788 case VT_NULL:
789 if (debugout) TRACE_(olerelay)("<null>");
790 return S_OK;
791 case VT_VARIANT: {
792 VARIANT *vt = (VARIANT*)arg;
794 if (readit) {
795 DWORD vttype;
796 TYPEDESC tdesc2;
797 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
798 if (hres) {
799 FIXME("vt type not read?\n");
800 return hres;
802 memset(&tdesc2,0,sizeof(tdesc2));
803 tdesc2.vt = vttype;
804 V_VT(vt) = vttype;
805 if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
806 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);
807 TRACE_(olerelay)(")");
808 return hres;
809 } else {
810 VariantInit(vt);
811 return S_OK;
814 case VT_ERROR:
815 case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT: case VT_R4:
816 case VT_UI2:
817 case VT_UI1:
818 if (readit) {
819 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
820 if (hres) FIXME("Failed to read integer 4 byte\n");
822 if (debugout) TRACE_(olerelay)("%lx",*arg);
823 return hres;
824 case VT_BSTR: {
825 WCHAR *str;
826 DWORD len;
828 if (readit) {
829 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
830 if (hres) {
831 FIXME("failed to read bstr klen\n");
832 return hres;
834 if (len == -1) {
835 *arg = 0;
836 if (debugout) TRACE_(olerelay)("<bstr NULL>");
837 } else {
838 str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
839 hres = xbuf_get(buf,(LPBYTE)str,len);
840 if (hres) {
841 FIXME("Failed to read BSTR.\n");
842 return hres;
844 *arg = (DWORD)SysAllocStringLen(str,len);
845 if (debugout) TRACE_(olerelay)("%s",relaystr(str));
846 HeapFree(GetProcessHeap(),0,str);
848 } else {
849 *arg = 0;
851 return S_OK;
853 case VT_PTR: {
854 DWORD cookie;
855 BOOL derefhere = 0;
857 derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
859 if (readit) {
860 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
861 if (hres) {
862 FIXME("Failed to load pointer cookie.\n");
863 return hres;
865 if (cookie != 0x42424242) {
866 if (debugout) TRACE_(olerelay)("NULL");
867 *arg = 0;
868 return S_OK;
870 if (debugout) TRACE_(olerelay)("*");
872 if (alloc) {
873 if (derefhere)
874 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
876 if (derefhere)
877 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
878 else
879 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
881 case VT_UNKNOWN:
882 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
883 if (alloc)
884 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
885 hres = S_OK;
886 if (readit)
887 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
888 if (debugout)
889 TRACE_(olerelay)("unk(%p)",arg);
890 return hres;
891 case VT_DISPATCH:
892 hres = S_OK;
893 if (readit)
894 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
895 if (debugout)
896 TRACE_(olerelay)("idisp(%p)",arg);
897 return hres;
898 case VT_VOID:
899 if (debugout) TRACE_(olerelay)("<void>");
900 return S_OK;
901 case VT_USERDEFINED: {
902 ITypeInfo *tinfo2;
903 TYPEATTR *tattr;
905 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
906 if (hres) {
907 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
908 return hres;
910 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
911 if (hres) {
912 FIXME("Could not get typeattr in VT_USERDEFINED.\n");
913 } else {
914 if (alloc)
915 *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
916 switch (tattr->typekind) {
917 case TKIND_DISPATCH:
918 case TKIND_INTERFACE:
919 if (readit)
920 hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
921 break;
922 case TKIND_RECORD: {
923 int i;
925 if (debugout) TRACE_(olerelay)("{");
926 for (i=0;i<tattr->cVars;i++) {
927 VARDESC *vdesc;
929 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
930 if (hres) {
931 FIXME("Could not get vardesc of %d\n",i);
932 return hres;
934 hres = deserialize_param(
935 tinfo2,
936 readit,
937 debugout,
938 alloc,
939 &vdesc->elemdescVar.tdesc,
940 (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
943 if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
945 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
946 memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
947 if (debugout) TRACE_(olerelay)("}");
948 break;
950 default:
951 ERR("Unhandled typekind %d\n",tattr->typekind);
952 hres = E_FAIL;
953 break;
956 if (hres)
957 FIXME("failed to stuballoc in TKIND_RECORD.\n");
958 ITypeInfo_Release(tinfo2);
959 return hres;
961 case VT_CARRAY: {
962 /* arg is pointing to the start of the array. */
963 ARRAYDESC *adesc = tdesc->u.lpadesc;
964 int arrsize,i;
965 arrsize = 1;
966 if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
967 for (i=0;i<adesc->cDims;i++)
968 arrsize *= adesc->rgbounds[i].cElements;
969 for (i=0;i<arrsize;i++)
970 deserialize_param(
971 tinfo,
972 readit,
973 debugout,
974 alloc,
975 &adesc->tdescElem,
976 (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),
979 return S_OK;
981 default:
982 ERR("No handler for VT type %d!\n",tdesc->vt);
983 return S_OK;
988 static HRESULT
989 deserialize_LPVOID_ptr(
990 ITypeInfo *tinfo,
991 BOOL readit,
992 BOOL debugout,
993 BOOL alloc,
994 TYPEDESC *tdesc,
995 DWORD *arg,
996 marshal_state *buf
998 HRESULT hres;
999 DWORD cookie;
1001 if ((tdesc->vt != VT_PTR) ||
1002 (tdesc->u.lptdesc->vt != VT_PTR) ||
1003 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
1005 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
1006 return E_FAIL;
1008 if (alloc)
1009 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
1010 if (readit) {
1011 hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));
1012 if (hres)
1013 return hres;
1014 if (cookie != 0x42424242) {
1015 *(DWORD*)*arg = 0;
1016 if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
1017 return S_OK;
1020 if (readit) {
1021 hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);
1022 if (hres)
1023 return hres;
1025 if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg);
1026 return S_OK;
1029 static HRESULT
1030 deserialize_DISPPARAM_ptr(
1031 ITypeInfo *tinfo,
1032 BOOL readit,
1033 BOOL debugout,
1034 BOOL alloc,
1035 TYPEDESC *tdesc,
1036 DWORD *arg,
1037 marshal_state *buf)
1039 DWORD cookie;
1040 DISPPARAMS *disps;
1041 HRESULT hres;
1042 int i;
1044 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
1045 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
1046 return E_FAIL;
1048 if (readit) {
1049 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1050 if (hres)
1051 return hres;
1052 if (cookie == 0) {
1053 *arg = 0;
1054 if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
1055 return S_OK;
1058 if (alloc)
1059 *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));
1060 disps = (DISPPARAMS*)*arg;
1061 if (!readit)
1062 return S_OK;
1063 hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));
1064 if (hres)
1065 return hres;
1066 if (alloc)
1067 disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);
1068 if (debugout) TRACE_(olerelay)("D{");
1069 for (i=0; i< disps->cArgs; i++) {
1070 TYPEDESC vdesc;
1072 vdesc.vt = VT_VARIANT;
1073 hres = deserialize_param(
1074 tinfo,
1075 readit,
1076 debugout,
1077 alloc,
1078 &vdesc,
1079 (DWORD*)(disps->rgvarg+i),
1083 if (debugout) TRACE_(olerelay)("}{");
1084 hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));
1085 if (hres)
1086 return hres;
1087 if (disps->cNamedArgs) {
1088 if (alloc)
1089 disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);
1090 for (i=0; i< disps->cNamedArgs; i++) {
1091 TYPEDESC vdesc;
1093 vdesc.vt = VT_UINT;
1094 hres = deserialize_param(
1095 tinfo,
1096 readit,
1097 debugout,
1098 alloc,
1099 &vdesc,
1100 (DWORD*)(disps->rgdispidNamedArgs+i),
1103 if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(",");
1106 if (debugout) TRACE_(olerelay)("}");
1107 return S_OK;
1110 /* Searches function, also in inherited interfaces */
1111 static HRESULT
1112 _get_funcdesc(
1113 ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname)
1115 int i = 0, j = 0;
1116 HRESULT hres;
1118 if (fname) *fname = NULL;
1119 if (iname) *iname = NULL;
1121 while (1) {
1122 hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
1123 if (hres) {
1124 ITypeInfo *tinfo2;
1125 HREFTYPE href;
1126 TYPEATTR *attr;
1128 hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
1129 if (hres) {
1130 FIXME("GetTypeAttr failed with %lx\n",hres);
1131 return hres;
1133 /* Not found, so look in inherited ifaces. */
1134 for (j=0;j<attr->cImplTypes;j++) {
1135 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
1136 if (hres) {
1137 FIXME("Did not find a reftype for interface offset %d?\n",j);
1138 break;
1140 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1141 if (hres) {
1142 FIXME("Did not find a typeinfo for reftype %ld?\n",href);
1143 continue;
1145 hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
1146 ITypeInfo_Release(tinfo2);
1147 if (!hres) return S_OK;
1149 return E_FAIL;
1151 if (((*fdesc)->oVft/4) == iMethod) {
1152 if (fname)
1153 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1154 if (iname)
1155 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1156 return S_OK;
1158 i++;
1160 return E_FAIL;
1163 static DWORD
1164 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1166 DWORD *args = ((DWORD*)&tpinfo)+1, *xargs;
1167 FUNCDESC *fdesc;
1168 HRESULT hres;
1169 int i, relaydeb = TRACE_ON(olerelay);
1170 marshal_state buf;
1171 RPCOLEMESSAGE msg;
1172 ULONG status;
1173 BSTR fname,iname;
1174 BSTR names[10];
1175 int nrofnames;
1177 EnterCriticalSection(&tpinfo->crit);
1179 hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
1180 if (hres) {
1181 ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1182 LeaveCriticalSection(&tpinfo->crit);
1183 return E_FAIL;
1186 if (relaydeb) {
1187 TRACE_(olerelay)("->");
1188 if (iname)
1189 TRACE_(olerelay)("%s:",relaystr(iname));
1190 if (fname)
1191 TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1192 else
1193 TRACE_(olerelay)("%d",method);
1194 TRACE_(olerelay)("(");
1195 if (iname) SysFreeString(iname);
1196 if (fname) SysFreeString(fname);
1198 /* Need them for hack below */
1199 memset(names,0,sizeof(names));
1200 if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1201 nrofnames = 0;
1202 if (nrofnames > sizeof(names)/sizeof(names[0]))
1203 ERR("Need more names!\n");
1205 memset(&buf,0,sizeof(buf));
1206 buf.iid = IID_IUnknown;
1207 if (method == 0) {
1208 xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
1209 if (relaydeb) TRACE_(olerelay)("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
1210 } else {
1211 xargs = args;
1212 for (i=0;i<fdesc->cParams;i++) {
1213 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1214 BOOL isserialized = FALSE;
1215 if (relaydeb) {
1216 if (i) TRACE_(olerelay)(",");
1217 if (i+1<nrofnames && names[i+1])
1218 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1220 /* No need to marshal other data than FIN */
1221 if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
1222 xargs+=_argsize(elem->tdesc.vt);
1223 if (relaydeb) TRACE_(olerelay)("[out]");
1224 continue;
1226 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1227 /* If the parameter is 'riid', we use it as interface IID
1228 * for a later ppvObject serialization.
1230 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1232 /* DISPPARAMS* needs special serializer */
1233 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1234 hres = serialize_DISPPARAM_ptr(
1235 tpinfo->tinfo,
1236 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1237 relaydeb,
1238 FALSE,
1239 &elem->tdesc,
1240 xargs,
1241 &buf
1243 isserialized = TRUE;
1245 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1246 hres = serialize_LPVOID_ptr(
1247 tpinfo->tinfo,
1248 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1249 relaydeb,
1250 FALSE,
1251 &elem->tdesc,
1252 xargs,
1253 &buf
1255 if (hres == S_OK)
1256 isserialized = TRUE;
1259 if (!isserialized)
1260 hres = serialize_param(
1261 tpinfo->tinfo,
1262 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1263 relaydeb,
1264 FALSE,
1265 &elem->tdesc,
1266 xargs,
1267 &buf
1270 if (hres) {
1271 FIXME("Failed to serialize param, hres %lx\n",hres);
1272 break;
1274 xargs+=_argsize(elem->tdesc.vt);
1277 if (relaydeb) TRACE_(olerelay)(")");
1278 memset(&msg,0,sizeof(msg));
1279 msg.cbBuffer = buf.curoff;
1280 msg.iMethod = method;
1281 hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
1282 if (hres) {
1283 FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
1284 LeaveCriticalSection(&tpinfo->crit);
1285 return hres;
1287 memcpy(msg.Buffer,buf.base,buf.curoff);
1288 if (relaydeb) TRACE_(olerelay)("\n");
1289 hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
1290 if (hres) {
1291 FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres);
1292 LeaveCriticalSection(&tpinfo->crit);
1293 return hres;
1296 if (relaydeb) TRACE_(olerelay)(" = %08lx (",status);
1297 if (buf.base)
1298 buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1299 else
1300 buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1301 buf.size = msg.cbBuffer;
1302 memcpy(buf.base,msg.Buffer,buf.size);
1303 buf.curoff = 0;
1304 if (method == 0) {
1305 _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
1306 if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1]));
1307 } else {
1308 xargs = args;
1309 for (i=0;i<fdesc->cParams;i++) {
1310 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1311 BOOL isdeserialized = FALSE;
1313 if (relaydeb) {
1314 if (i) TRACE_(olerelay)(",");
1315 if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1317 /* No need to marshal other data than FOUT I think */
1318 if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
1319 xargs += _argsize(elem->tdesc.vt);
1320 if (relaydeb) TRACE_(olerelay)("[in]");
1321 continue;
1323 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1324 /* If the parameter is 'riid', we use it as interface IID
1325 * for a later ppvObject serialization.
1327 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1329 /* deserialize DISPPARAM */
1330 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1331 hres = deserialize_DISPPARAM_ptr(
1332 tpinfo->tinfo,
1333 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1334 relaydeb,
1335 FALSE,
1336 &(elem->tdesc),
1337 xargs,
1338 &buf
1340 if (hres) {
1341 FIXME("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1342 break;
1344 isdeserialized = TRUE;
1346 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1347 hres = deserialize_LPVOID_ptr(
1348 tpinfo->tinfo,
1349 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1350 relaydeb,
1351 FALSE,
1352 &elem->tdesc,
1353 xargs,
1354 &buf
1356 if (hres == S_OK)
1357 isdeserialized = TRUE;
1360 if (!isdeserialized)
1361 hres = deserialize_param(
1362 tpinfo->tinfo,
1363 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1364 relaydeb,
1365 FALSE,
1366 &(elem->tdesc),
1367 xargs,
1368 &buf
1370 if (hres) {
1371 FIXME("Failed to unmarshall param, hres %lx\n",hres);
1372 break;
1374 xargs += _argsize(elem->tdesc.vt);
1377 if (relaydeb) TRACE_(olerelay)(")\n");
1378 HeapFree(GetProcessHeap(),0,buf.base);
1380 LeaveCriticalSection(&tpinfo->crit);
1382 return status;
1385 static HRESULT WINAPI
1386 PSFacBuf_CreateProxy(
1387 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1388 IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1390 HRESULT hres;
1391 ITypeInfo *tinfo;
1392 int i, nroffuncs;
1393 FUNCDESC *fdesc;
1394 TMProxyImpl *proxy;
1396 TRACE("(...%s...)\n",debugstr_guid(riid));
1397 hres = _get_typeinfo_for_iid(riid,&tinfo);
1398 if (hres) {
1399 FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
1400 return hres;
1402 nroffuncs = _nroffuncs(tinfo);
1403 proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1404 if (!proxy) return E_OUTOFMEMORY;
1406 assert(sizeof(TMAsmProxy) == 12);
1408 proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1409 if (!proxy->asmstubs) {
1410 ERR("Could not commit pages for proxy thunks\n");
1411 CoTaskMemFree(proxy);
1412 return E_OUTOFMEMORY;
1415 InitializeCriticalSection(&proxy->crit);
1417 proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1418 for (i=0;i<nroffuncs;i++) {
1419 int nrofargs;
1420 TMAsmProxy *xasm = proxy->asmstubs+i;
1422 /* nrofargs without This */
1423 switch (i) {
1424 case 0: nrofargs = 2;
1425 break;
1426 case 1: case 2: nrofargs = 0;
1427 break;
1428 default: {
1429 int j;
1430 hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
1431 if (hres) {
1432 FIXME("GetFuncDesc %lx should not fail here.\n",hres);
1433 return hres;
1435 /* some args take more than 4 byte on the stack */
1436 nrofargs = 0;
1437 for (j=0;j<fdesc->cParams;j++)
1438 nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
1440 if (fdesc->callconv != CC_STDCALL) {
1441 ERR("calling convention is not stdcall????\n");
1442 return E_FAIL;
1444 break;
1447 /* popl %eax - return ptr
1448 * pushl <nr>
1449 * pushl %eax
1450 * call xCall
1451 * lret <nr> (+4)
1454 * arg3 arg2 arg1 <method> <returnptr>
1456 xasm->popleax = 0x58;
1457 xasm->pushlval = 0x6a;
1458 xasm->nr = i;
1459 xasm->pushleax = 0x50;
1460 xasm->lcall = 0xe8; /* relative jump */
1461 xasm->xcall = (DWORD)xCall;
1462 xasm->xcall -= (DWORD)&(xasm->lret);
1463 xasm->lret = 0xc2;
1464 xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
1465 proxy->lpvtbl[i] = xasm;
1467 proxy->lpvtbl2 = &tmproxyvtable;
1468 /* 1 reference for the proxy and 1 for the object */
1469 proxy->ref = 2;
1470 proxy->tinfo = tinfo;
1471 memcpy(&proxy->iid,riid,sizeof(*riid));
1472 *ppv = (LPVOID)proxy;
1473 *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1474 return S_OK;
1477 typedef struct _TMStubImpl {
1478 IRpcStubBufferVtbl *lpvtbl;
1479 ULONG ref;
1481 LPUNKNOWN pUnk;
1482 ITypeInfo *tinfo;
1483 IID iid;
1484 } TMStubImpl;
1486 static HRESULT WINAPI
1487 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1489 if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1490 *ppv = (LPVOID)iface;
1491 IRpcStubBuffer_AddRef(iface);
1492 return S_OK;
1494 FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1495 return E_NOINTERFACE;
1498 static ULONG WINAPI
1499 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1501 TMStubImpl *This = (TMStubImpl *)iface;
1503 TRACE("(%p) before %lu\n", This, This->ref);
1505 return InterlockedIncrement(&This->ref);
1508 static ULONG WINAPI
1509 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1511 ULONG refs;
1512 TMStubImpl *This = (TMStubImpl *)iface;
1514 TRACE("(%p) after %lu\n", This, This->ref-1);
1516 refs = InterlockedDecrement(&This->ref);
1517 if (!refs)
1519 IRpcStubBuffer_Disconnect(iface);
1520 CoTaskMemFree(This);
1522 return refs;
1525 static HRESULT WINAPI
1526 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1528 TMStubImpl *This = (TMStubImpl *)iface;
1530 TRACE("(%p)->(%p)\n", This, pUnkServer);
1532 IUnknown_AddRef(pUnkServer);
1533 This->pUnk = pUnkServer;
1534 return S_OK;
1537 static void WINAPI
1538 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1540 TMStubImpl *This = (TMStubImpl *)iface;
1542 TRACE("(%p)->()\n", This);
1544 IUnknown_Release(This->pUnk);
1545 This->pUnk = NULL;
1546 return;
1549 static HRESULT WINAPI
1550 TMStubImpl_Invoke(
1551 LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1553 int i;
1554 FUNCDESC *fdesc;
1555 TMStubImpl *This = (TMStubImpl *)iface;
1556 HRESULT hres;
1557 DWORD *args, res, *xargs, nrofargs;
1558 marshal_state buf;
1559 int nrofnames;
1560 BSTR names[10];
1562 memset(&buf,0,sizeof(buf));
1563 buf.size = xmsg->cbBuffer;
1564 buf.base = xmsg->Buffer;
1565 buf.curoff = 0;
1566 buf.iid = IID_IUnknown;
1568 TRACE("...\n");
1569 if (xmsg->iMethod == 0) { /* QI */
1570 IID xiid;
1571 /* in: IID, out: <iface> */
1573 xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
1574 buf.curoff = 0;
1575 hres = _marshal_interface(&buf,&xiid,This->pUnk);
1576 xmsg->Buffer = buf.base; /* Might have been reallocated */
1577 xmsg->cbBuffer = buf.size;
1578 return hres;
1580 hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
1581 if (hres) {
1582 FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1583 return hres;
1585 /* Need them for hack below */
1586 memset(names,0,sizeof(names));
1587 ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1588 if (nrofnames > sizeof(names)/sizeof(names[0])) {
1589 ERR("Need more names!\n");
1592 /*dump_FUNCDESC(fdesc);*/
1593 nrofargs = 0;
1594 for (i=0;i<fdesc->cParams;i++)
1595 nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1596 args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1597 if (!args) return E_OUTOFMEMORY;
1599 /* Allocate all stuff used by call. */
1600 xargs = args+1;
1601 for (i=0;i<fdesc->cParams;i++) {
1602 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1603 BOOL isdeserialized = FALSE;
1605 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1606 /* If the parameter is 'riid', we use it as interface IID
1607 * for a later ppvObject serialization.
1609 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1611 /* deserialize DISPPARAM */
1612 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1613 hres = deserialize_DISPPARAM_ptr(
1614 This->tinfo,
1615 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1616 FALSE,
1617 TRUE,
1618 &(elem->tdesc),
1619 xargs,
1620 &buf
1622 if (hres) {
1623 FIXME("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1624 break;
1626 isdeserialized = TRUE;
1628 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1629 hres = deserialize_LPVOID_ptr(
1630 This->tinfo,
1631 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1632 FALSE,
1633 TRUE,
1634 &elem->tdesc,
1635 xargs,
1636 &buf
1638 if (hres == S_OK)
1639 isdeserialized = TRUE;
1642 if (!isdeserialized)
1643 hres = deserialize_param(
1644 This->tinfo,
1645 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1646 FALSE,
1647 TRUE,
1648 &(elem->tdesc),
1649 xargs,
1650 &buf
1652 xargs += _argsize(elem->tdesc.vt);
1653 if (hres) {
1654 FIXME("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
1655 break;
1658 hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1659 if (hres) {
1660 ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
1661 return hres;
1663 res = _invoke(
1664 (*((FARPROC**)args[0]))[fdesc->oVft/4],
1665 fdesc->callconv,
1666 (xargs-args),
1667 args
1669 IUnknown_Release((LPUNKNOWN)args[0]);
1670 buf.curoff = 0;
1671 xargs = args+1;
1672 for (i=0;i<fdesc->cParams;i++) {
1673 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1674 BOOL isserialized = FALSE;
1676 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1677 /* If the parameter is 'riid', we use it as interface IID
1678 * for a later ppvObject serialization.
1680 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1682 /* DISPPARAMS* needs special serializer */
1683 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1684 hres = serialize_DISPPARAM_ptr(
1685 This->tinfo,
1686 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1687 FALSE,
1688 TRUE,
1689 &elem->tdesc,
1690 xargs,
1691 &buf
1693 isserialized = TRUE;
1695 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1696 hres = serialize_LPVOID_ptr(
1697 This->tinfo,
1698 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1699 FALSE,
1700 TRUE,
1701 &elem->tdesc,
1702 xargs,
1703 &buf
1705 if (hres == S_OK)
1706 isserialized = TRUE;
1709 if (!isserialized)
1710 hres = serialize_param(
1711 This->tinfo,
1712 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1713 FALSE,
1714 TRUE,
1715 &elem->tdesc,
1716 xargs,
1717 &buf
1719 xargs += _argsize(elem->tdesc.vt);
1720 if (hres) {
1721 FIXME("Failed to stuballoc param, hres %lx\n",hres);
1722 break;
1725 /* might need to use IRpcChannelBuffer_GetBuffer ? */
1726 xmsg->cbBuffer = buf.curoff;
1727 xmsg->Buffer = buf.base;
1728 HeapFree(GetProcessHeap(),0,args);
1729 return res;
1732 static LPRPCSTUBBUFFER WINAPI
1733 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1734 FIXME("Huh (%s)?\n",debugstr_guid(riid));
1735 return NULL;
1738 static ULONG WINAPI
1739 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1740 TMStubImpl *This = (TMStubImpl *)iface;
1742 return This->ref; /*FIXME? */
1745 static HRESULT WINAPI
1746 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1747 return E_NOTIMPL;
1750 static void WINAPI
1751 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1752 return;
1755 IRpcStubBufferVtbl tmstubvtbl = {
1756 TMStubImpl_QueryInterface,
1757 TMStubImpl_AddRef,
1758 TMStubImpl_Release,
1759 TMStubImpl_Connect,
1760 TMStubImpl_Disconnect,
1761 TMStubImpl_Invoke,
1762 TMStubImpl_IsIIDSupported,
1763 TMStubImpl_CountRefs,
1764 TMStubImpl_DebugServerQueryInterface,
1765 TMStubImpl_DebugServerRelease
1768 static HRESULT WINAPI
1769 PSFacBuf_CreateStub(
1770 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1771 IRpcStubBuffer** ppStub
1773 HRESULT hres;
1774 ITypeInfo *tinfo;
1775 TMStubImpl *stub;
1777 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1778 hres = _get_typeinfo_for_iid(riid,&tinfo);
1779 if (hres) {
1780 FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
1781 return hres;
1783 stub = CoTaskMemAlloc(sizeof(TMStubImpl));
1784 if (!stub)
1785 return E_OUTOFMEMORY;
1786 stub->lpvtbl = &tmstubvtbl;
1787 stub->ref = 1;
1788 stub->tinfo = tinfo;
1789 memcpy(&(stub->iid),riid,sizeof(*riid));
1790 hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1791 *ppStub = (LPRPCSTUBBUFFER)stub;
1792 TRACE("IRpcStubBuffer: %p\n", stub);
1793 if (hres)
1794 FIXME("Connect to pUnkServer failed?\n");
1795 return hres;
1798 static IPSFactoryBufferVtbl psfacbufvtbl = {
1799 PSFacBuf_QueryInterface,
1800 PSFacBuf_AddRef,
1801 PSFacBuf_Release,
1802 PSFacBuf_CreateProxy,
1803 PSFacBuf_CreateStub
1806 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1807 static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
1809 /***********************************************************************
1810 * DllGetClassObject [OLE32.63]
1812 HRESULT WINAPI
1813 TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1815 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1816 *ppv = &lppsfac;
1817 return S_OK;
1819 return E_NOINTERFACE;