Fixed some issues found by winapi_check.
[wine/dcerpc.git] / dlls / oleaut32 / tmarshal.c
bloba8c3e641a9055c74adca4a96bf897dc22ab7e842
1 /*
2 * TYPELIB Marshaler
4 * Copyright 2002 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <ctype.h>
29 #include "winerror.h"
30 #include "winnls.h"
31 #include "winreg.h"
32 #include "winuser.h"
34 #include "ole2.h"
35 #include "wine/unicode.h"
36 #include "wine/obj_base.h"
37 #include "wine/obj_channel.h"
38 #include "wine/obj_storage.h"
39 #include "heap.h"
40 #include "ole2disp.h"
41 #include "typelib.h"
42 #include "wine/debug.h"
43 #include "ntddk.h"
45 static const WCHAR riidW[5] = {'r','i','i','d',0};
46 static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};
47 static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};
49 WINE_DEFAULT_DEBUG_CHANNEL(ole);
50 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
52 typedef struct _marshal_state {
53 LPBYTE base;
54 int size;
55 int curoff;
57 BOOL thisisiid;
58 IID iid; /* HACK: for VT_VOID */
59 } marshal_state;
61 static HRESULT
62 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
63 while (buf->size - buf->curoff < size) {
64 if (buf->base) {
65 buf->size += 100;
66 buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
67 if (!buf->base)
68 return E_OUTOFMEMORY;
69 } else {
70 buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
71 buf->size = 32;
72 if (!buf->base)
73 return E_OUTOFMEMORY;
76 memcpy(buf->base+buf->curoff,stuff,size);
77 buf->curoff += size;
78 return S_OK;
81 static HRESULT
82 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
83 if (buf->size < buf->curoff+size) return E_FAIL;
84 memcpy(stuff,buf->base+buf->curoff,size);
85 buf->curoff += size;
86 return S_OK;
89 static HRESULT
90 xbuf_skip(marshal_state *buf, DWORD size) {
91 if (buf->size < buf->curoff+size) return E_FAIL;
92 buf->curoff += size;
93 return S_OK;
96 static HRESULT
97 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
98 IStream *pStm;
99 ULARGE_INTEGER newpos;
100 LARGE_INTEGER seekto;
101 ULONG res;
102 HRESULT hres;
103 DWORD xsize;
105 TRACE("...%s...\n",debugstr_guid(riid));
106 *pUnk = NULL;
107 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
108 if (hres) return hres;
109 if (xsize == 0) return S_OK;
110 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
111 if (hres) {
112 FIXME("Stream create failed %lx\n",hres);
113 return hres;
115 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
116 if (hres) { FIXME("stream write %lx\n",hres); return hres; }
117 memset(&seekto,0,sizeof(seekto));
118 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
119 if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;}
120 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
121 if (hres) {
122 FIXME("Marshaling interface %s failed with %lx\n",debugstr_guid(riid),hres);
123 return hres;
125 IStream_Release(pStm);
126 return xbuf_skip(buf,xsize);
129 static HRESULT
130 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
131 LPUNKNOWN newiface;
132 LPBYTE tempbuf;
133 IStream *pStm;
134 STATSTG ststg;
135 ULARGE_INTEGER newpos;
136 LARGE_INTEGER seekto;
137 ULONG res;
138 DWORD xsize;
139 HRESULT hres;
141 hres = S_OK;
142 if (!pUnk)
143 goto fail;
145 TRACE("...%s...\n",debugstr_guid(riid));
146 hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
147 if (hres) {
148 TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
149 goto fail;
151 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
152 if (hres) {
153 FIXME("Stream create failed %lx\n",hres);
154 goto fail;
156 hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
157 IUnknown_Release(newiface);
158 if (hres) {
159 FIXME("Marshaling interface %s failed with %lx\n",
160 debugstr_guid(riid),hres
162 goto fail;
164 hres = IStream_Stat(pStm,&ststg,0);
165 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.s.LowPart);
166 memset(&seekto,0,sizeof(seekto));
167 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
168 if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;}
169 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.s.LowPart,&res);
170 if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;}
171 IStream_Release(pStm);
172 xsize = ststg.cbSize.s.LowPart;
173 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
174 hres = xbuf_add(buf,tempbuf,ststg.cbSize.s.LowPart);
175 HeapFree(GetProcessHeap(),0,tempbuf);
176 return hres;
177 fail:
178 xsize = 0;
179 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
180 return hres;
183 /********************* OLE Proxy/Stub Factory ********************************/
184 static HRESULT WINAPI
185 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
186 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
187 *ppv = (LPVOID)iface;
188 /* No ref counting, static class */
189 return S_OK;
191 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
192 return E_NOINTERFACE;
195 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
196 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
198 static HRESULT
199 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
200 HRESULT hres;
201 HKEY ikey;
202 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
203 char tlfn[260];
204 OLECHAR tlfnW[260];
205 DWORD tlguidlen, verlen, type, tlfnlen;
206 ITypeLib *tl;
208 sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
209 riid->Data1, riid->Data2, riid->Data3,
210 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
211 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
214 if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
215 FIXME("No %s key found.\n",interfacekey);
216 return E_FAIL;
218 type = (1<<REG_SZ);
219 tlguidlen = sizeof(tlguid);
220 if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
221 FIXME("Getting typelib guid failed.\n");
222 RegCloseKey(ikey);
223 return E_FAIL;
225 type = (1<<REG_SZ);
226 verlen = sizeof(ver);
227 if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
228 FIXME("Could not get version value?\n");
229 RegCloseKey(ikey);
230 return E_FAIL;
232 RegCloseKey(ikey);
233 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
234 tlfnlen = sizeof(tlfn);
235 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
236 FIXME("Could not get typelib fn?\n");
237 return E_FAIL;
239 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
240 hres = LoadTypeLib(tlfnW,&tl);
241 if (hres) {
242 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
243 return hres;
245 hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
246 if (hres) {
247 ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
248 ITypeLib_Release(tl);
249 return hres;
251 /* FIXME: do this? ITypeLib_Release(tl); */
252 return hres;
255 /* Determine nr of functions. Since we use the toplevel interface and all
256 * inherited ones have lower numbers, we are ok to not to descent into
257 * the inheritance tree I think.
259 static int _nroffuncs(ITypeInfo *tinfo) {
260 int n, max = 0;
261 FUNCDESC *fdesc;
262 HRESULT hres;
264 n=0;
265 while (1) {
266 hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
267 if (fdesc->oVft/4 > max)
268 max = fdesc->oVft/4;
269 if (hres)
270 return max+1;
271 n++;
273 /*NOTREACHED*/
276 typedef struct _TMAsmProxy {
277 BYTE popleax;
278 BYTE pushlval;
279 BYTE nr;
280 BYTE pushleax;
281 BYTE lcall;
282 DWORD xcall;
283 BYTE lret;
284 WORD bytestopop;
285 } WINE_PACKED TMAsmProxy;
287 typedef struct _TMProxyImpl {
288 DWORD *lpvtbl;
289 ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl2;
290 DWORD ref;
292 TMAsmProxy *asmstubs;
293 ITypeInfo* tinfo;
294 IRpcChannelBuffer* chanbuf;
295 IID iid;
296 } TMProxyImpl;
298 static HRESULT WINAPI
299 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) {
300 TRACE("()\n");
301 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
302 *ppv = (LPVOID)iface;
303 IRpcProxyBuffer_AddRef(iface);
304 return S_OK;
306 FIXME("no interface for %s\n",debugstr_guid(riid));
307 return E_NOINTERFACE;
310 static ULONG WINAPI
311 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) {
312 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
314 TRACE("()\n");
315 This->ref++;
316 return This->ref;
319 static ULONG WINAPI
320 TMProxyImpl_Release(LPRPCPROXYBUFFER iface) {
321 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
323 TRACE("()\n");
324 This->ref--;
325 if (This->ref) return This->ref;
326 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
327 HeapFree(GetProcessHeap(),0,This);
328 return 0;
331 static HRESULT WINAPI
332 TMProxyImpl_Connect(
333 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer
335 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
337 TRACE("(%p)\n",pRpcChannelBuffer);
338 This->chanbuf = pRpcChannelBuffer;
339 IRpcChannelBuffer_AddRef(This->chanbuf);
340 return S_OK;
343 static void WINAPI
344 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) {
345 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
347 FIXME("()\n");
348 IRpcChannelBuffer_Release(This->chanbuf);
349 This->chanbuf = NULL;
353 static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = {
354 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
355 TMProxyImpl_QueryInterface,
356 TMProxyImpl_AddRef,
357 TMProxyImpl_Release,
358 TMProxyImpl_Connect,
359 TMProxyImpl_Disconnect
362 /* how much space do we use on stack in DWORD steps. */
363 int const
364 _argsize(DWORD vt) {
365 switch (vt) {
366 case VT_DATE:
367 return sizeof(DATE)/sizeof(DWORD);
368 case VT_VARIANT:
369 return (sizeof(VARIANT)+3)/sizeof(DWORD);
370 default:
371 return 1;
375 static int
376 _xsize(TYPEDESC *td) {
377 switch (td->vt) {
378 case VT_DATE:
379 return sizeof(DATE);
380 case VT_VARIANT:
381 return sizeof(VARIANT)+3;
382 case VT_CARRAY: {
383 int i, arrsize = 1;
384 ARRAYDESC *adesc = td->u.lpadesc;
386 for (i=0;i<adesc->cDims;i++)
387 arrsize *= adesc->rgbounds[i].cElements;
388 return arrsize*_xsize(&adesc->tdescElem);
390 case VT_UI2:
391 case VT_I2:
392 return 2;
393 case VT_UI1:
394 case VT_I1:
395 return 1;
396 default:
397 return 4;
401 static HRESULT
402 serialize_param(
403 ITypeInfo *tinfo,
404 BOOL writeit,
405 BOOL debugout,
406 BOOL dealloc,
407 TYPEDESC *tdesc,
408 DWORD *arg,
409 marshal_state *buf
411 HRESULT hres = S_OK;
413 TRACE("(tdesc.vt %d)\n",tdesc->vt);
415 switch (tdesc->vt) {
416 case VT_EMPTY: /* nothing. empty variant for instance */
417 return S_OK;
418 case VT_BOOL:
419 case VT_ERROR:
420 case VT_UI4:
421 case VT_UINT:
422 case VT_I4:
423 case VT_UI2:
424 case VT_UI1:
425 hres = S_OK;
426 if (debugout) MESSAGE("%lx",*arg);
427 if (writeit)
428 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
429 return hres;
430 case VT_VARIANT: {
431 TYPEDESC tdesc2;
432 VARIANT *vt = (VARIANT*)arg;
433 DWORD vttype = V_VT(vt);
435 if (debugout) MESSAGE("Vt(%ld)(",vttype);
436 tdesc2.vt = vttype;
437 if (writeit) {
438 hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
439 if (hres) return hres;
441 /* need to recurse since we need to free the stuff */
442 hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);
443 if (debugout) MESSAGE(")");
444 return hres;
446 case VT_BSTR: {
447 if (debugout) {
448 if (arg)
449 MESSAGE("%s",debugstr_w((BSTR)*arg));
450 else
451 MESSAGE("<bstr NULL>");
453 if (writeit) {
454 if (!*arg) {
455 DWORD fakelen = -1;
456 hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
457 if (hres)
458 return hres;
459 } else {
460 DWORD *bstr = ((DWORD*)(*arg))-1;
462 hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
463 if (hres)
464 return hres;
467 if (dealloc && arg)
468 SysFreeString((BSTR)arg);
469 return S_OK;
471 case VT_PTR: {
472 DWORD cookie;
474 if (debugout) MESSAGE("*");
475 if (writeit) {
476 cookie = *arg ? 0x42424242 : 0;
477 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
478 if (hres)
479 return hres;
481 if (!*arg) {
482 if (debugout) MESSAGE("NULL");
483 return S_OK;
485 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
486 if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
487 return hres;
489 case VT_UNKNOWN:
490 if (debugout) MESSAGE("unk(0x%lx)",*arg);
491 if (writeit)
492 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
493 return hres;
494 case VT_DISPATCH:
495 if (debugout) MESSAGE("idisp(0x%lx)",*arg);
496 if (writeit)
497 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
498 return hres;
499 case VT_VOID:
500 if (debugout) MESSAGE("<void>");
501 return S_OK;
502 case VT_USERDEFINED: {
503 ITypeInfo *tinfo2;
504 TYPEATTR *tattr;
506 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
507 if (hres) {
508 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
509 return hres;
511 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
512 switch (tattr->typekind) {
513 case TKIND_INTERFACE:
514 if (writeit)
515 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
516 break;
517 case TKIND_RECORD: {
518 int i;
519 if (debugout) MESSAGE("{");
520 for (i=0;i<tattr->cVars;i++) {
521 VARDESC *vdesc;
522 ELEMDESC *elem2;
523 TYPEDESC *tdesc2;
525 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
526 if (hres) {
527 FIXME("Could not get vardesc of %d\n",i);
528 return hres;
530 /* Need them for hack below */
532 memset(names,0,sizeof(names));
533 hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
534 if (nrofnames > sizeof(names)/sizeof(names[0])) {
535 ERR("Need more names!\n");
537 if (!hres && debugout)
538 MESSAGE("%s=",debugstr_w(names[0]));
540 elem2 = &vdesc->elemdescVar;
541 tdesc2 = &elem2->tdesc;
542 hres = serialize_param(
543 tinfo2,
544 writeit,
545 debugout,
546 dealloc,
547 tdesc2,
548 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
551 if (hres!=S_OK)
552 return hres;
553 if (debugout && (i<(tattr->cVars-1)))
554 MESSAGE(",");
556 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
557 memcpy(&(buf->iid),arg,sizeof(buf->iid));
558 if (debugout) MESSAGE("}");
559 break;
561 default:
562 FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
563 hres = E_FAIL;
564 break;
566 ITypeInfo_Release(tinfo2);
567 return hres;
569 case VT_CARRAY: {
570 ARRAYDESC *adesc = tdesc->u.lpadesc;
571 int i, arrsize = 1;
573 if (debugout) MESSAGE("carr");
574 for (i=0;i<adesc->cDims;i++) {
575 if (debugout) MESSAGE("[%ld]",adesc->rgbounds[i].cElements);
576 arrsize *= adesc->rgbounds[i].cElements;
578 if (debugout) MESSAGE("[");
579 for (i=0;i<arrsize;i++) {
580 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
581 if (hres)
582 return hres;
583 if (debugout && (i<arrsize-1)) MESSAGE(",");
585 if (debugout) MESSAGE("]");
586 return S_OK;
588 default:
589 ERR("Unhandled marshal type %d.\n",tdesc->vt);
590 return S_OK;
594 static HRESULT
595 serialize_LPVOID_ptr(
596 ITypeInfo *tinfo,
597 BOOL writeit,
598 BOOL debugout,
599 BOOL dealloc,
600 TYPEDESC *tdesc,
601 DWORD *arg,
602 marshal_state *buf
604 HRESULT hres;
605 DWORD cookie;
607 if ((tdesc->vt != VT_PTR) ||
608 (tdesc->u.lptdesc->vt != VT_PTR) ||
609 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
611 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
612 return E_FAIL;
614 cookie = (*arg) ? 0x42424242: 0x0;
615 if (writeit) {
616 hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
617 if (hres)
618 return hres;
620 if (!*arg) {
621 if (debugout) MESSAGE("<lpvoid NULL>");
622 return S_OK;
624 if (debugout)
625 MESSAGE("ppv(%p)",*(LPUNKNOWN*)*arg);
626 if (writeit) {
627 hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
628 if (hres)
629 return hres;
631 if (dealloc)
632 HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
633 return S_OK;
636 static HRESULT
637 serialize_DISPPARAM_ptr(
638 ITypeInfo *tinfo,
639 BOOL writeit,
640 BOOL debugout,
641 BOOL dealloc,
642 TYPEDESC *tdesc,
643 DWORD *arg,
644 marshal_state *buf
646 DWORD cookie;
647 HRESULT hres;
648 DISPPARAMS *disp;
649 int i;
651 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
652 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
653 return E_FAIL;
656 cookie = *arg ? 0x42424242 : 0x0;
657 if (writeit) {
658 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
659 if (hres)
660 return hres;
662 if (!*arg) {
663 if (debugout) MESSAGE("<DISPPARAMS NULL>");
664 return S_OK;
666 disp = (DISPPARAMS*)*arg;
667 if (writeit) {
668 hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
669 if (hres)
670 return hres;
672 if (debugout) MESSAGE("D{");
673 for (i=0;i<disp->cArgs;i++) {
674 TYPEDESC vtdesc;
676 vtdesc.vt = VT_VARIANT;
677 serialize_param(
678 tinfo,
679 writeit,
680 debugout,
681 dealloc,
682 &vtdesc,
683 (DWORD*)(disp->rgvarg+i),
686 if (debugout && (i<disp->cArgs-1))
687 MESSAGE(",");
689 if (dealloc)
690 HeapFree(GetProcessHeap(),0,disp->rgvarg);
691 if (writeit) {
692 hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
693 if (hres)
694 return hres;
696 if (debugout) MESSAGE("}{");
697 for (i=0;i<disp->cNamedArgs;i++) {
698 TYPEDESC vtdesc;
700 vtdesc.vt = VT_UINT;
701 serialize_param(
702 tinfo,
703 writeit,
704 debugout,
705 dealloc,
706 &vtdesc,
707 (DWORD*)(disp->rgdispidNamedArgs+i),
710 if (debugout && (i<disp->cNamedArgs-1))
711 MESSAGE(",");
713 if (debugout) MESSAGE("}");
714 if (dealloc) {
715 HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
716 HeapFree(GetProcessHeap(),0,disp);
718 return S_OK;
721 static HRESULT
722 deserialize_param(
723 ITypeInfo *tinfo,
724 BOOL readit,
725 BOOL debugout,
726 BOOL alloc,
727 TYPEDESC *tdesc,
728 DWORD *arg,
729 marshal_state *buf
731 HRESULT hres = S_OK;
733 TRACE("vt %d at %p\n",tdesc->vt,arg);
735 while (1) {
736 switch (tdesc->vt) {
737 case VT_EMPTY:
738 if (debugout) MESSAGE("<empty>");
739 return S_OK;
740 case VT_NULL:
741 if (debugout) MESSAGE("<null>");
742 return S_OK;
743 case VT_VARIANT: {
744 VARIANT *vt = (VARIANT*)arg;
746 if (readit) {
747 DWORD vttype;
748 TYPEDESC tdesc2;
749 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
750 if (hres) {
751 FIXME("vt type not read?\n");
752 return hres;
754 memset(&tdesc2,0,sizeof(tdesc2));
755 tdesc2.vt = vttype;
756 V_VT(vt) = vttype;
757 if (debugout) MESSAGE("Vt(%ld)(",vttype);
758 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);
759 MESSAGE(")");
760 return hres;
761 } else {
762 VariantInit(vt);
763 return S_OK;
766 case VT_ERROR:
767 case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT:
768 case VT_UI2:
769 case VT_UI1:
770 if (readit) {
771 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
772 if (hres) FIXME("Failed to read integer 4 byte\n");
774 if (debugout) MESSAGE("%lx",*arg);
775 return hres;
776 case VT_BSTR: {
777 WCHAR *str;
778 DWORD len;
780 if (readit) {
781 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
782 if (hres) {
783 FIXME("failed to read bstr klen\n");
784 return hres;
786 if (len == -1) {
787 *arg = 0;
788 if (debugout) MESSAGE("<bstr NULL>");
789 } else {
790 str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
791 hres = xbuf_get(buf,(LPBYTE)str,len);
792 if (hres) {
793 FIXME("Failed to read BSTR.\n");
794 return hres;
796 *arg = (DWORD)SysAllocStringLen(str,len);
797 if (debugout) MESSAGE("%s",debugstr_w(str));
798 HeapFree(GetProcessHeap(),0,str);
800 } else {
801 *arg = 0;
803 return S_OK;
805 case VT_PTR: {
806 DWORD cookie;
807 BOOL derefhere = 0;
809 derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
811 if (readit) {
812 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
813 if (hres) {
814 FIXME("Failed to load pointer cookie.\n");
815 return hres;
817 if (cookie != 0x42424242) {
818 if (debugout) MESSAGE("NULL");
819 *arg = 0;
820 return S_OK;
822 if (debugout) MESSAGE("*");
824 if (alloc) {
825 if (derefhere)
826 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
828 if (derefhere)
829 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
830 else
831 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
833 case VT_UNKNOWN:
834 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
835 if (alloc)
836 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
837 hres = S_OK;
838 if (readit)
839 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
840 if (debugout)
841 MESSAGE("unk(%p)",arg);
842 return hres;
843 case VT_DISPATCH:
844 hres = S_OK;
845 if (readit)
846 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
847 if (debugout)
848 MESSAGE("idisp(%p)",arg);
849 return hres;
850 case VT_VOID:
851 if (debugout) MESSAGE("<void>");
852 return S_OK;
853 case VT_USERDEFINED: {
854 ITypeInfo *tinfo2;
855 TYPEATTR *tattr;
857 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
858 if (hres) {
859 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
860 return hres;
862 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
863 if (hres) {
864 FIXME("Could not get typeattr in VT_USERDEFINED.\n");
865 } else {
866 if (alloc)
867 *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
868 switch (tattr->typekind) {
869 case TKIND_INTERFACE:
870 if (readit)
871 hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
872 break;
873 case TKIND_RECORD: {
874 int i;
876 if (debugout) MESSAGE("{");
877 for (i=0;i<tattr->cVars;i++) {
878 VARDESC *vdesc;
880 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
881 if (hres) {
882 FIXME("Could not get vardesc of %d\n",i);
883 return hres;
885 hres = deserialize_param(
886 tinfo2,
887 readit,
888 debugout,
889 alloc,
890 &vdesc->elemdescVar.tdesc,
891 (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
894 if (debugout && (i<tattr->cVars-1)) MESSAGE(",");
896 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
897 memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
898 if (debugout) MESSAGE("}");
899 break;
901 default:
902 FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
903 hres = E_FAIL;
904 break;
907 if (hres)
908 FIXME("failed to stuballoc in TKIND_RECORD.\n");
909 ITypeInfo_Release(tinfo2);
910 return hres;
912 case VT_CARRAY: {
913 /* arg is pointing to the start of the array. */
914 ARRAYDESC *adesc = tdesc->u.lpadesc;
915 int arrsize,i;
916 arrsize = 1;
917 if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
918 for (i=0;i<adesc->cDims;i++)
919 arrsize *= adesc->rgbounds[i].cElements;
920 for (i=0;i<arrsize;i++)
921 deserialize_param(
922 tinfo,
923 readit,
924 debugout,
925 alloc,
926 &adesc->tdescElem,
927 (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),
930 return S_OK;
932 default:
933 ERR("No handler for VT type %d!\n",tdesc->vt);
934 return S_OK;
939 static HRESULT
940 deserialize_LPVOID_ptr(
941 ITypeInfo *tinfo,
942 BOOL readit,
943 BOOL debugout,
944 BOOL alloc,
945 TYPEDESC *tdesc,
946 DWORD *arg,
947 marshal_state *buf
949 HRESULT hres;
950 DWORD cookie;
952 if ((tdesc->vt != VT_PTR) ||
953 (tdesc->u.lptdesc->vt != VT_PTR) ||
954 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
956 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
957 return E_FAIL;
959 if (alloc)
960 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
961 if (readit) {
962 hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));
963 if (hres)
964 return hres;
965 if (cookie != 0x42424242) {
966 *(DWORD*)*arg = 0;
967 if (debugout) MESSAGE("<lpvoid NULL>");
968 return S_OK;
971 if (readit) {
972 hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);
973 if (hres)
974 return hres;
976 if (debugout) MESSAGE("ppv(%p)",(LPVOID)*arg);
977 return S_OK;
980 static HRESULT
981 deserialize_DISPPARAM_ptr(
982 ITypeInfo *tinfo,
983 BOOL readit,
984 BOOL debugout,
985 BOOL alloc,
986 TYPEDESC *tdesc,
987 DWORD *arg,
988 marshal_state *buf
990 DWORD cookie;
991 DISPPARAMS *disps;
992 HRESULT hres;
993 int i;
995 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
996 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
997 return E_FAIL;
999 if (readit) {
1000 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1001 if (hres)
1002 return hres;
1003 if (cookie == 0) {
1004 *arg = 0;
1005 if (debugout) MESSAGE("<DISPPARAMS NULL>");
1006 return S_OK;
1009 if (alloc)
1010 *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));
1011 disps = (DISPPARAMS*)*arg;
1012 if (!readit)
1013 return S_OK;
1014 hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));
1015 if (hres)
1016 return hres;
1017 if (alloc)
1018 disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);
1019 if (debugout) MESSAGE("D{");
1020 for (i=0; i< disps->cArgs; i++) {
1021 TYPEDESC vdesc;
1023 vdesc.vt = VT_VARIANT;
1024 hres = deserialize_param(
1025 tinfo,
1026 readit,
1027 debugout,
1028 alloc,
1029 &vdesc,
1030 (DWORD*)(disps->rgvarg+i),
1034 if (debugout) MESSAGE("}{");
1035 hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));
1036 if (hres)
1037 return hres;
1038 if (disps->cNamedArgs) {
1039 if (alloc)
1040 disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);
1041 for (i=0; i< disps->cNamedArgs; i++) {
1042 TYPEDESC vdesc;
1044 vdesc.vt = VT_UINT;
1045 hres = deserialize_param(
1046 tinfo,
1047 readit,
1048 debugout,
1049 alloc,
1050 &vdesc,
1051 (DWORD*)(disps->rgdispidNamedArgs+i),
1054 if (debugout && i<(disps->cNamedArgs-1)) MESSAGE(",");
1057 if (debugout) MESSAGE("}");
1058 return S_OK;
1061 /* Searches function, also in inherited interfaces */
1062 static HRESULT
1063 _get_funcdesc(
1064 ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname
1066 int i = 0, j = 0;
1067 HRESULT hres;
1069 if (fname) *fname = NULL;
1070 if (iname) *iname = NULL;
1072 while (1) {
1073 hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
1074 if (hres) {
1075 ITypeInfo *tinfo2;
1076 HREFTYPE href;
1077 TYPEATTR *attr;
1079 hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
1080 if (hres) {
1081 FIXME("GetTypeAttr failed with %lx\n",hres);
1082 return hres;
1084 /* Not found, so look in inherited ifaces. */
1085 for (j=0;j<attr->cImplTypes;j++) {
1086 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
1087 if (hres) {
1088 FIXME("Did not find a reftype for interface offset %d?\n",j);
1089 break;
1091 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1092 if (hres) {
1093 FIXME("Did not find a typeinfo for reftype %ld?\n",href);
1094 continue;
1096 hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
1097 ITypeInfo_Release(tinfo2);
1098 if (!hres) return S_OK;
1100 return E_FAIL;
1102 if (((*fdesc)->oVft/4) == iMethod) {
1103 if (fname)
1104 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1105 if (iname)
1106 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1107 return S_OK;
1109 i++;
1111 return E_FAIL;
1114 static DWORD
1115 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
1116 DWORD *args = ((DWORD*)&tpinfo)+1, *xargs;
1117 FUNCDESC *fdesc;
1118 HRESULT hres;
1119 int i, relaydeb = TRACE_ON(olerelay);
1120 marshal_state buf;
1121 RPCOLEMESSAGE msg;
1122 ULONG status;
1123 BSTR fname,iname;
1124 BSTR names[10];
1125 int nrofnames;
1127 hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
1128 if (hres) {
1129 ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1130 return 0;
1133 /*dump_FUNCDESC(fdesc);*/
1134 if (relaydeb) {
1135 TRACE_(olerelay)("->");
1136 if (iname)
1137 MESSAGE("%s:",debugstr_w(iname));
1138 if (fname)
1139 MESSAGE("%s(%d)",debugstr_w(fname),method);
1140 else
1141 MESSAGE("%d",method);
1142 MESSAGE("(");
1143 if (iname) SysFreeString(iname);
1144 if (fname) SysFreeString(fname);
1146 /* Need them for hack below */
1147 memset(names,0,sizeof(names));
1148 if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1149 nrofnames = 0;
1150 if (nrofnames > sizeof(names)/sizeof(names[0]))
1151 ERR("Need more names!\n");
1153 memset(&buf,0,sizeof(buf));
1154 buf.iid = IID_IUnknown;
1155 if (method == 0) {
1156 xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
1157 if (relaydeb) MESSAGE("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
1158 } else {
1159 xargs = args;
1160 for (i=0;i<fdesc->cParams;i++) {
1161 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1162 BOOL isserialized = FALSE;
1163 if (relaydeb) {
1164 if (i) MESSAGE(",");
1165 if (i+1<nrofnames && names[i+1])
1166 MESSAGE("%s=",debugstr_w(names[i+1]));
1168 /* No need to marshal other data than FIN */
1169 if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
1170 xargs+=_argsize(elem->tdesc.vt);
1171 if (relaydeb) MESSAGE("[out]");
1172 continue;
1174 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1175 /* If the parameter is 'riid', we use it as interface IID
1176 * for a later ppvObject serialization.
1178 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1180 /* DISPPARAMS* needs special serializer */
1181 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1182 hres = serialize_DISPPARAM_ptr(
1183 tpinfo->tinfo,
1184 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1185 relaydeb,
1186 FALSE,
1187 &elem->tdesc,
1188 xargs,
1189 &buf
1191 isserialized = TRUE;
1193 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1194 hres = serialize_LPVOID_ptr(
1195 tpinfo->tinfo,
1196 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1197 relaydeb,
1198 FALSE,
1199 &elem->tdesc,
1200 xargs,
1201 &buf
1203 if (hres == S_OK)
1204 isserialized = TRUE;
1207 if (!isserialized)
1208 hres = serialize_param(
1209 tpinfo->tinfo,
1210 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1211 relaydeb,
1212 FALSE,
1213 &elem->tdesc,
1214 xargs,
1215 &buf
1218 if (hres) {
1219 FIXME("Failed to serialize param, hres %lx\n",hres);
1220 break;
1222 xargs+=_argsize(elem->tdesc.vt);
1225 if (relaydeb) MESSAGE(")");
1226 memset(&msg,0,sizeof(msg));
1227 msg.cbBuffer = buf.curoff;
1228 msg.iMethod = method;
1229 hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
1230 if (hres) {
1231 FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
1232 return hres;
1234 memcpy(msg.Buffer,buf.base,buf.curoff);
1235 if (relaydeb) MESSAGE("\n");
1236 hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
1237 if (hres) {
1238 FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres);
1239 return hres;
1241 relaydeb = TRACE_ON(olerelay);
1242 if (relaydeb) MESSAGE(" = %08lx (",status);
1243 if (buf.base)
1244 buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1245 else
1246 buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1247 buf.size = msg.cbBuffer;
1248 memcpy(buf.base,msg.Buffer,buf.size);
1249 buf.curoff = 0;
1250 if (method == 0) {
1251 _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
1252 if (relaydeb) MESSAGE("[in],%p",*((DWORD**)args[1]));
1253 } else {
1254 xargs = args;
1255 for (i=0;i<fdesc->cParams;i++) {
1256 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1257 BOOL isdeserialized = FALSE;
1259 if (relaydeb) {
1260 if (i) MESSAGE(",");
1261 if (i+1<nrofnames && names[i+1]) MESSAGE("%s=",debugstr_w(names[i+1]));
1263 /* No need to marshal other data than FOUT I think */
1264 if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
1265 xargs += _argsize(elem->tdesc.vt);
1266 if (relaydeb) MESSAGE("[in]");
1267 continue;
1269 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1270 /* If the parameter is 'riid', we use it as interface IID
1271 * for a later ppvObject serialization.
1273 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1275 /* deserialize DISPPARAM */
1276 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1277 hres = deserialize_DISPPARAM_ptr(
1278 tpinfo->tinfo,
1279 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1280 relaydeb,
1281 FALSE,
1282 &(elem->tdesc),
1283 xargs,
1284 &buf
1286 if (hres) {
1287 FIXME("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1288 break;
1290 isdeserialized = TRUE;
1292 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1293 hres = deserialize_LPVOID_ptr(
1294 tpinfo->tinfo,
1295 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1296 relaydeb,
1297 FALSE,
1298 &elem->tdesc,
1299 xargs,
1300 &buf
1302 if (hres == S_OK)
1303 isdeserialized = TRUE;
1306 if (!isdeserialized)
1307 hres = deserialize_param(
1308 tpinfo->tinfo,
1309 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1310 relaydeb,
1311 FALSE,
1312 &(elem->tdesc),
1313 xargs,
1314 &buf
1316 if (hres) {
1317 FIXME("Failed to unmarshall param, hres %lx\n",hres);
1318 break;
1320 xargs += _argsize(elem->tdesc.vt);
1323 if (relaydeb) MESSAGE(")\n\n");
1324 HeapFree(GetProcessHeap(),0,buf.base);
1325 return status;
1328 static HRESULT WINAPI
1329 PSFacBuf_CreateProxy(
1330 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1331 IRpcProxyBuffer **ppProxy, LPVOID *ppv
1333 HRESULT hres;
1334 ITypeInfo *tinfo;
1335 int i, nroffuncs;
1336 FUNCDESC *fdesc;
1337 TMProxyImpl *proxy;
1339 TRACE("(...%s...)\n",debugstr_guid(riid));
1340 hres = _get_typeinfo_for_iid(riid,&tinfo);
1341 if (hres) {
1342 FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
1343 return hres;
1345 nroffuncs = _nroffuncs(tinfo);
1346 proxy = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMProxyImpl));
1347 if (!proxy) return E_OUTOFMEMORY;
1348 proxy->asmstubs=HeapAlloc(GetProcessHeap(),0,sizeof(TMAsmProxy)*nroffuncs);
1350 assert(sizeof(TMAsmProxy) == 12);
1352 proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1353 for (i=0;i<nroffuncs;i++) {
1354 int nrofargs;
1355 TMAsmProxy *xasm = proxy->asmstubs+i;
1357 /* nrofargs without This */
1358 switch (i) {
1359 case 0: nrofargs = 2;
1360 break;
1361 case 1: case 2: nrofargs = 0;
1362 break;
1363 default: {
1364 int j;
1365 hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
1366 if (hres) {
1367 FIXME("GetFuncDesc %lx should not fail here.\n",hres);
1368 return hres;
1370 /* some args take more than 4 byte on the stack */
1371 nrofargs = 0;
1372 for (j=0;j<fdesc->cParams;j++)
1373 nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
1375 if (fdesc->callconv != CC_STDCALL) {
1376 ERR("calling convention is not stdcall????\n");
1377 return E_FAIL;
1379 break;
1382 /* popl %eax - return ptr
1383 * pushl <nr>
1384 * pushl %eax
1385 * call xCall
1386 * lret <nr> (+4)
1389 * arg3 arg2 arg1 <method> <returnptr>
1391 xasm->popleax = 0x58;
1392 xasm->pushlval = 0x6a;
1393 xasm->nr = i;
1394 xasm->pushleax = 0x50;
1395 xasm->lcall = 0xe8; /* relative jump */
1396 xasm->xcall = (DWORD)xCall;
1397 xasm->xcall -= (DWORD)&(xasm->lret);
1398 xasm->lret = 0xc2;
1399 xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
1400 proxy->lpvtbl[i] = (DWORD)xasm;
1402 proxy->lpvtbl2 = &tmproxyvtable;
1403 proxy->ref = 2;
1404 proxy->tinfo = tinfo;
1405 memcpy(&proxy->iid,riid,sizeof(*riid));
1406 *ppv = (LPVOID)proxy;
1407 *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1408 return S_OK;
1411 typedef struct _TMStubImpl {
1412 ICOM_VTABLE(IRpcStubBuffer) *lpvtbl;
1413 DWORD ref;
1415 LPUNKNOWN pUnk;
1416 ITypeInfo *tinfo;
1417 IID iid;
1418 } TMStubImpl;
1420 static HRESULT WINAPI
1421 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
1422 if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1423 *ppv = (LPVOID)iface;
1424 IRpcStubBuffer_AddRef(iface);
1425 return S_OK;
1427 FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1428 return E_NOINTERFACE;
1431 static ULONG WINAPI
1432 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) {
1433 ICOM_THIS(TMStubImpl,iface);
1435 This->ref++;
1436 return This->ref;
1439 static ULONG WINAPI
1440 TMStubImpl_Release(LPRPCSTUBBUFFER iface) {
1441 ICOM_THIS(TMStubImpl,iface);
1443 This->ref--;
1444 if (This->ref)
1445 return This->ref;
1446 HeapFree(GetProcessHeap(),0,This);
1447 return 0;
1450 static HRESULT WINAPI
1451 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) {
1452 ICOM_THIS(TMStubImpl,iface);
1454 IUnknown_AddRef(pUnkServer);
1455 This->pUnk = pUnkServer;
1456 return S_OK;
1459 static void WINAPI
1460 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) {
1461 ICOM_THIS(TMStubImpl,iface);
1463 IUnknown_Release(This->pUnk);
1464 This->pUnk = NULL;
1465 return;
1468 static HRESULT WINAPI
1469 TMStubImpl_Invoke(
1470 LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf
1472 int i;
1473 FUNCDESC *fdesc;
1474 ICOM_THIS(TMStubImpl,iface);
1475 HRESULT hres;
1476 DWORD *args, res, *xargs, nrofargs;
1477 marshal_state buf;
1478 int nrofnames;
1479 BSTR names[10];
1481 memset(&buf,0,sizeof(buf));
1482 buf.size = xmsg->cbBuffer;
1483 buf.base = xmsg->Buffer;
1484 buf.curoff = 0;
1485 buf.iid = IID_IUnknown;
1487 TRACE("...\n");
1488 if (xmsg->iMethod == 0) { /* QI */
1489 IID xiid;
1490 /* in: IID, out: <iface> */
1492 xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
1493 buf.curoff = 0;
1494 hres = _marshal_interface(&buf,&xiid,This->pUnk);
1495 xmsg->Buffer = buf.base; /* Might have been reallocated */
1496 xmsg->cbBuffer = buf.size;
1497 return hres;
1499 hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
1500 if (hres) {
1501 FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1502 return hres;
1504 /* Need them for hack below */
1505 memset(names,0,sizeof(names));
1506 ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1507 if (nrofnames > sizeof(names)/sizeof(names[0])) {
1508 ERR("Need more names!\n");
1511 /*dump_FUNCDESC(fdesc);*/
1512 nrofargs = 0;
1513 for (i=0;i<fdesc->cParams;i++)
1514 nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1515 args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1516 if (!args) return E_OUTOFMEMORY;
1518 /* Allocate all stuff used by call. */
1519 xargs = args+1;
1520 for (i=0;i<fdesc->cParams;i++) {
1521 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1522 BOOL isdeserialized = FALSE;
1524 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1525 /* If the parameter is 'riid', we use it as interface IID
1526 * for a later ppvObject serialization.
1528 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1530 /* deserialize DISPPARAM */
1531 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1532 hres = deserialize_DISPPARAM_ptr(
1533 This->tinfo,
1534 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1535 FALSE,
1536 TRUE,
1537 &(elem->tdesc),
1538 xargs,
1539 &buf
1541 if (hres) {
1542 FIXME("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1543 break;
1545 isdeserialized = TRUE;
1547 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1548 hres = deserialize_LPVOID_ptr(
1549 This->tinfo,
1550 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1551 FALSE,
1552 TRUE,
1553 &elem->tdesc,
1554 xargs,
1555 &buf
1557 if (hres == S_OK)
1558 isdeserialized = TRUE;
1561 if (!isdeserialized)
1562 hres = deserialize_param(
1563 This->tinfo,
1564 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1565 FALSE,
1566 TRUE,
1567 &(elem->tdesc),
1568 xargs,
1569 &buf
1571 xargs += _argsize(elem->tdesc.vt);
1572 if (hres) {
1573 FIXME("Failed to deserialize param %s, hres %lx\n",debugstr_w(names[i+1]),hres);
1574 break;
1577 hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1578 if (hres) {
1579 ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
1580 return hres;
1582 res = _invoke(
1583 (*((LPVOID**)args[0]))[fdesc->oVft/4],
1584 fdesc->callconv,
1585 (xargs-args),
1586 args
1588 IUnknown_Release((LPUNKNOWN)args[0]);
1589 buf.curoff = 0;
1590 xargs = args+1;
1591 for (i=0;i<fdesc->cParams;i++) {
1592 ELEMDESC *elem = fdesc->lprgelemdescParam+i;
1593 BOOL isserialized = FALSE;
1595 if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1596 /* If the parameter is 'riid', we use it as interface IID
1597 * for a later ppvObject serialization.
1599 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1601 /* DISPPARAMS* needs special serializer */
1602 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1603 hres = serialize_DISPPARAM_ptr(
1604 This->tinfo,
1605 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1606 FALSE,
1607 TRUE,
1608 &elem->tdesc,
1609 xargs,
1610 &buf
1612 isserialized = TRUE;
1614 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1615 hres = serialize_LPVOID_ptr(
1616 This->tinfo,
1617 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1618 FALSE,
1619 TRUE,
1620 &elem->tdesc,
1621 xargs,
1622 &buf
1624 if (hres == S_OK)
1625 isserialized = TRUE;
1628 if (!isserialized)
1629 hres = serialize_param(
1630 This->tinfo,
1631 elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1632 FALSE,
1633 TRUE,
1634 &elem->tdesc,
1635 xargs,
1636 &buf
1638 xargs += _argsize(elem->tdesc.vt);
1639 if (hres) {
1640 FIXME("Failed to stuballoc param, hres %lx\n",hres);
1641 break;
1644 /* might need to use IRpcChannelBuffer_GetBuffer ? */
1645 xmsg->cbBuffer = buf.curoff;
1646 xmsg->Buffer = buf.base;
1647 HeapFree(GetProcessHeap(),0,args);
1648 return res;
1651 static LPRPCSTUBBUFFER WINAPI
1652 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1653 FIXME("Huh (%s)?\n",debugstr_guid(riid));
1654 return NULL;
1657 static ULONG WINAPI
1658 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1659 ICOM_THIS(TMStubImpl,iface);
1661 return This->ref; /*FIXME? */
1664 static HRESULT WINAPI
1665 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1666 return E_NOTIMPL;
1669 static void WINAPI
1670 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1671 return;
1674 ICOM_VTABLE(IRpcStubBuffer) tmstubvtbl = {
1675 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1676 TMStubImpl_QueryInterface,
1677 TMStubImpl_AddRef,
1678 TMStubImpl_Release,
1679 TMStubImpl_Connect,
1680 TMStubImpl_Disconnect,
1681 TMStubImpl_Invoke,
1682 TMStubImpl_IsIIDSupported,
1683 TMStubImpl_CountRefs,
1684 TMStubImpl_DebugServerQueryInterface,
1685 TMStubImpl_DebugServerRelease
1688 static HRESULT WINAPI
1689 PSFacBuf_CreateStub(
1690 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1691 IRpcStubBuffer** ppStub
1693 HRESULT hres;
1694 ITypeInfo *tinfo;
1695 TMStubImpl *stub;
1697 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1698 hres = _get_typeinfo_for_iid(riid,&tinfo);
1699 if (hres) {
1700 FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
1701 return hres;
1703 stub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMStubImpl));
1704 if (!stub)
1705 return E_OUTOFMEMORY;
1706 stub->lpvtbl = &tmstubvtbl;
1707 stub->ref = 1;
1708 stub->tinfo = tinfo;
1709 memcpy(&(stub->iid),riid,sizeof(*riid));
1710 hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1711 *ppStub = (LPRPCSTUBBUFFER)stub;
1712 if (hres)
1713 FIXME("Connect to pUnkServer failed?\n");
1714 return hres;
1717 static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
1718 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1719 PSFacBuf_QueryInterface,
1720 PSFacBuf_AddRef,
1721 PSFacBuf_Release,
1722 PSFacBuf_CreateProxy,
1723 PSFacBuf_CreateStub
1726 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1727 static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
1729 /***********************************************************************
1730 * DllGetClassObject [OLE32.63]
1732 HRESULT WINAPI
1733 TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1735 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1736 *ppv = &lppsfac;
1737 return S_OK;
1739 return E_NOINTERFACE;