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