Move the test strings into their own array and convert them to unicode
[wine/multimedia.git] / dlls / oleaut32 / tmarshal.c
blobcbd2cfb99402a478fbcb66c39476df6ddae7250c
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 "heap.h"
37 #include "ole2disp.h"
38 #include "typelib.h"
39 #include "wine/debug.h"
40 #include "winternl.h"
42 static const WCHAR riidW[5] = {'r','i','i','d',0};
43 static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0};
44 static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0};
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
47 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
49 typedef struct _marshal_state {
50 LPBYTE base;
51 int size;
52 int curoff;
54 BOOL thisisiid;
55 IID iid; /* HACK: for VT_VOID */
56 } marshal_state;
58 static HRESULT
59 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
60 while (buf->size - buf->curoff < size) {
61 if (buf->base) {
62 buf->size += 100;
63 buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
64 if (!buf->base)
65 return E_OUTOFMEMORY;
66 } else {
67 buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
68 buf->size = 32;
69 if (!buf->base)
70 return E_OUTOFMEMORY;
73 memcpy(buf->base+buf->curoff,stuff,size);
74 buf->curoff += size;
75 return S_OK;
78 static HRESULT
79 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
80 if (buf->size < buf->curoff+size) return E_FAIL;
81 memcpy(stuff,buf->base+buf->curoff,size);
82 buf->curoff += size;
83 return S_OK;
86 static HRESULT
87 xbuf_skip(marshal_state *buf, DWORD size) {
88 if (buf->size < buf->curoff+size) return E_FAIL;
89 buf->curoff += size;
90 return S_OK;
93 static HRESULT
94 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
95 IStream *pStm;
96 ULARGE_INTEGER newpos;
97 LARGE_INTEGER seekto;
98 ULONG res;
99 HRESULT hres;
100 DWORD xsize;
102 TRACE("...%s...\n",debugstr_guid(riid));
103 *pUnk = NULL;
104 hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
105 if (hres) return hres;
106 if (xsize == 0) return S_OK;
107 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
108 if (hres) {
109 FIXME("Stream create failed %lx\n",hres);
110 return hres;
112 hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
113 if (hres) { FIXME("stream write %lx\n",hres); return hres; }
114 memset(&seekto,0,sizeof(seekto));
115 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
116 if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;}
117 hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
118 if (hres) {
119 FIXME("Marshaling interface %s failed with %lx\n",debugstr_guid(riid),hres);
120 return hres;
122 IStream_Release(pStm);
123 return xbuf_skip(buf,xsize);
126 static HRESULT
127 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
128 LPUNKNOWN newiface;
129 LPBYTE tempbuf;
130 IStream *pStm;
131 STATSTG ststg;
132 ULARGE_INTEGER newpos;
133 LARGE_INTEGER seekto;
134 ULONG res;
135 DWORD xsize;
136 HRESULT hres;
138 hres = S_OK;
139 if (!pUnk)
140 goto fail;
142 TRACE("...%s...\n",debugstr_guid(riid));
143 hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
144 if (hres) {
145 TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
146 goto fail;
148 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
149 if (hres) {
150 FIXME("Stream create failed %lx\n",hres);
151 goto fail;
153 hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
154 IUnknown_Release(newiface);
155 if (hres) {
156 FIXME("Marshaling interface %s failed with %lx\n",
157 debugstr_guid(riid),hres
159 goto fail;
161 hres = IStream_Stat(pStm,&ststg,0);
162 tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.s.LowPart);
163 memset(&seekto,0,sizeof(seekto));
164 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
165 if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;}
166 hres = IStream_Read(pStm,tempbuf,ststg.cbSize.s.LowPart,&res);
167 if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;}
168 IStream_Release(pStm);
169 xsize = ststg.cbSize.s.LowPart;
170 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
171 hres = xbuf_add(buf,tempbuf,ststg.cbSize.s.LowPart);
172 HeapFree(GetProcessHeap(),0,tempbuf);
173 return hres;
174 fail:
175 xsize = 0;
176 xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
177 return hres;
180 /********************* OLE Proxy/Stub Factory ********************************/
181 static HRESULT WINAPI
182 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
183 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
184 *ppv = (LPVOID)iface;
185 /* No ref counting, static class */
186 return S_OK;
188 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
189 return E_NOINTERFACE;
192 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
193 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
195 static HRESULT
196 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
197 HRESULT hres;
198 HKEY ikey;
199 char tlguid[200],typelibkey[300],interfacekey[300],ver[100];
200 char tlfn[260];
201 OLECHAR tlfnW[260];
202 DWORD tlguidlen, verlen, type, tlfnlen;
203 ITypeLib *tl;
205 sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
206 riid->Data1, riid->Data2, riid->Data3,
207 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
208 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
211 if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
212 FIXME("No %s key found.\n",interfacekey);
213 return E_FAIL;
215 type = (1<<REG_SZ);
216 tlguidlen = sizeof(tlguid);
217 if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
218 FIXME("Getting typelib guid failed.\n");
219 RegCloseKey(ikey);
220 return E_FAIL;
222 type = (1<<REG_SZ);
223 verlen = sizeof(ver);
224 if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
225 FIXME("Could not get version value?\n");
226 RegCloseKey(ikey);
227 return E_FAIL;
229 RegCloseKey(ikey);
230 sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
231 tlfnlen = sizeof(tlfn);
232 if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
233 FIXME("Could not get typelib fn?\n");
234 return E_FAIL;
236 MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
237 hres = LoadTypeLib(tlfnW,&tl);
238 if (hres) {
239 ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
240 return hres;
242 hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
243 if (hres) {
244 ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
245 ITypeLib_Release(tl);
246 return hres;
248 /* FIXME: do this? ITypeLib_Release(tl); */
249 return hres;
252 /* Determine nr of functions. Since we use the toplevel interface and all
253 * inherited ones have lower numbers, we are ok to not to descent into
254 * the inheritance tree I think.
256 static int _nroffuncs(ITypeInfo *tinfo) {
257 int n, max = 0;
258 FUNCDESC *fdesc;
259 HRESULT hres;
261 n=0;
262 while (1) {
263 hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
264 if (fdesc->oVft/4 > max)
265 max = fdesc->oVft/4;
266 if (hres)
267 return max+1;
268 n++;
270 /*NOTREACHED*/
273 typedef struct _TMAsmProxy {
274 BYTE popleax;
275 BYTE pushlval;
276 BYTE nr;
277 BYTE pushleax;
278 BYTE lcall;
279 DWORD xcall;
280 BYTE lret;
281 WORD bytestopop;
282 } WINE_PACKED TMAsmProxy;
284 typedef struct _TMProxyImpl {
285 DWORD *lpvtbl;
286 ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl2;
287 DWORD ref;
289 TMAsmProxy *asmstubs;
290 ITypeInfo* tinfo;
291 IRpcChannelBuffer* chanbuf;
292 IID iid;
293 } TMProxyImpl;
295 static HRESULT WINAPI
296 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) {
297 TRACE("()\n");
298 if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
299 *ppv = (LPVOID)iface;
300 IRpcProxyBuffer_AddRef(iface);
301 return S_OK;
303 FIXME("no interface for %s\n",debugstr_guid(riid));
304 return E_NOINTERFACE;
307 static ULONG WINAPI
308 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) {
309 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
311 TRACE("()\n");
312 This->ref++;
313 return This->ref;
316 static ULONG WINAPI
317 TMProxyImpl_Release(LPRPCPROXYBUFFER iface) {
318 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
320 TRACE("()\n");
321 This->ref--;
322 if (This->ref) return This->ref;
323 if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
324 HeapFree(GetProcessHeap(),0,This);
325 return 0;
328 static HRESULT WINAPI
329 TMProxyImpl_Connect(
330 LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer
332 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
334 TRACE("(%p)\n",pRpcChannelBuffer);
335 This->chanbuf = pRpcChannelBuffer;
336 IRpcChannelBuffer_AddRef(This->chanbuf);
337 return S_OK;
340 static void WINAPI
341 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) {
342 ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
344 FIXME("()\n");
345 IRpcChannelBuffer_Release(This->chanbuf);
346 This->chanbuf = NULL;
350 static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = {
351 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
352 TMProxyImpl_QueryInterface,
353 TMProxyImpl_AddRef,
354 TMProxyImpl_Release,
355 TMProxyImpl_Connect,
356 TMProxyImpl_Disconnect
359 /* how much space do we use on stack in DWORD steps. */
360 int const
361 _argsize(DWORD vt) {
362 switch (vt) {
363 case VT_DATE:
364 return sizeof(DATE)/sizeof(DWORD);
365 case VT_VARIANT:
366 return (sizeof(VARIANT)+3)/sizeof(DWORD);
367 default:
368 return 1;
372 static int
373 _xsize(TYPEDESC *td) {
374 switch (td->vt) {
375 case VT_DATE:
376 return sizeof(DATE);
377 case VT_VARIANT:
378 return sizeof(VARIANT)+3;
379 case VT_CARRAY: {
380 int i, arrsize = 1;
381 ARRAYDESC *adesc = td->u.lpadesc;
383 for (i=0;i<adesc->cDims;i++)
384 arrsize *= adesc->rgbounds[i].cElements;
385 return arrsize*_xsize(&adesc->tdescElem);
387 case VT_UI2:
388 case VT_I2:
389 return 2;
390 case VT_UI1:
391 case VT_I1:
392 return 1;
393 default:
394 return 4;
398 static HRESULT
399 serialize_param(
400 ITypeInfo *tinfo,
401 BOOL writeit,
402 BOOL debugout,
403 BOOL dealloc,
404 TYPEDESC *tdesc,
405 DWORD *arg,
406 marshal_state *buf
408 HRESULT hres = S_OK;
410 TRACE("(tdesc.vt %d)\n",tdesc->vt);
412 switch (tdesc->vt) {
413 case VT_EMPTY: /* nothing. empty variant for instance */
414 return S_OK;
415 case VT_BOOL:
416 case VT_ERROR:
417 case VT_UI4:
418 case VT_UINT:
419 case VT_I4:
420 case VT_R4:
421 case VT_UI2:
422 case VT_UI1:
423 hres = S_OK;
424 if (debugout) MESSAGE("%lx",*arg);
425 if (writeit)
426 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
427 return hres;
428 case VT_VARIANT: {
429 TYPEDESC tdesc2;
430 VARIANT *vt = (VARIANT*)arg;
431 DWORD vttype = V_VT(vt);
433 if (debugout) MESSAGE("Vt(%ld)(",vttype);
434 tdesc2.vt = vttype;
435 if (writeit) {
436 hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
437 if (hres) return hres;
439 /* need to recurse since we need to free the stuff */
440 hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);
441 if (debugout) MESSAGE(")");
442 return hres;
444 case VT_BSTR: {
445 if (debugout) {
446 if (arg)
447 MESSAGE("%s",debugstr_w((BSTR)*arg));
448 else
449 MESSAGE("<bstr NULL>");
451 if (writeit) {
452 if (!*arg) {
453 DWORD fakelen = -1;
454 hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
455 if (hres)
456 return hres;
457 } else {
458 DWORD *bstr = ((DWORD*)(*arg))-1;
460 hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
461 if (hres)
462 return hres;
465 if (dealloc && arg)
466 SysFreeString((BSTR)arg);
467 return S_OK;
469 case VT_PTR: {
470 DWORD cookie;
472 if (debugout) MESSAGE("*");
473 if (writeit) {
474 cookie = *arg ? 0x42424242 : 0;
475 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
476 if (hres)
477 return hres;
479 if (!*arg) {
480 if (debugout) MESSAGE("NULL");
481 return S_OK;
483 hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
484 if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
485 return hres;
487 case VT_UNKNOWN:
488 if (debugout) MESSAGE("unk(0x%lx)",*arg);
489 if (writeit)
490 hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
491 return hres;
492 case VT_DISPATCH:
493 if (debugout) MESSAGE("idisp(0x%lx)",*arg);
494 if (writeit)
495 hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
496 return hres;
497 case VT_VOID:
498 if (debugout) MESSAGE("<void>");
499 return S_OK;
500 case VT_USERDEFINED: {
501 ITypeInfo *tinfo2;
502 TYPEATTR *tattr;
504 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
505 if (hres) {
506 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
507 return hres;
509 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
510 switch (tattr->typekind) {
511 case TKIND_DISPATCH:
512 case TKIND_INTERFACE:
513 if (writeit)
514 hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
515 break;
516 case TKIND_RECORD: {
517 int i;
518 if (debugout) MESSAGE("{");
519 for (i=0;i<tattr->cVars;i++) {
520 VARDESC *vdesc;
521 ELEMDESC *elem2;
522 TYPEDESC *tdesc2;
524 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
525 if (hres) {
526 FIXME("Could not get vardesc of %d\n",i);
527 return hres;
529 /* Need them for hack below */
531 memset(names,0,sizeof(names));
532 hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
533 if (nrofnames > sizeof(names)/sizeof(names[0])) {
534 ERR("Need more names!\n");
536 if (!hres && debugout)
537 MESSAGE("%s=",debugstr_w(names[0]));
539 elem2 = &vdesc->elemdescVar;
540 tdesc2 = &elem2->tdesc;
541 hres = serialize_param(
542 tinfo2,
543 writeit,
544 debugout,
545 dealloc,
546 tdesc2,
547 (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
550 if (hres!=S_OK)
551 return hres;
552 if (debugout && (i<(tattr->cVars-1)))
553 MESSAGE(",");
555 if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
556 memcpy(&(buf->iid),arg,sizeof(buf->iid));
557 if (debugout) MESSAGE("}");
558 break;
560 default:
561 FIXME("Unhandled typekind %d\n",tattr->typekind);
562 hres = E_FAIL;
563 break;
565 ITypeInfo_Release(tinfo2);
566 return hres;
568 case VT_CARRAY: {
569 ARRAYDESC *adesc = tdesc->u.lpadesc;
570 int i, arrsize = 1;
572 if (debugout) MESSAGE("carr");
573 for (i=0;i<adesc->cDims;i++) {
574 if (debugout) MESSAGE("[%ld]",adesc->rgbounds[i].cElements);
575 arrsize *= adesc->rgbounds[i].cElements;
577 if (debugout) MESSAGE("[");
578 for (i=0;i<arrsize;i++) {
579 hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
580 if (hres)
581 return hres;
582 if (debugout && (i<arrsize-1)) MESSAGE(",");
584 if (debugout) MESSAGE("]");
585 return S_OK;
587 default:
588 ERR("Unhandled marshal type %d.\n",tdesc->vt);
589 return S_OK;
593 static HRESULT
594 serialize_LPVOID_ptr(
595 ITypeInfo *tinfo,
596 BOOL writeit,
597 BOOL debugout,
598 BOOL dealloc,
599 TYPEDESC *tdesc,
600 DWORD *arg,
601 marshal_state *buf
603 HRESULT hres;
604 DWORD cookie;
606 if ((tdesc->vt != VT_PTR) ||
607 (tdesc->u.lptdesc->vt != VT_PTR) ||
608 (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
610 FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
611 return E_FAIL;
613 cookie = (*arg) ? 0x42424242: 0x0;
614 if (writeit) {
615 hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
616 if (hres)
617 return hres;
619 if (!*arg) {
620 if (debugout) MESSAGE("<lpvoid NULL>");
621 return S_OK;
623 if (debugout)
624 MESSAGE("ppv(%p)",*(LPUNKNOWN*)*arg);
625 if (writeit) {
626 hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
627 if (hres)
628 return hres;
630 if (dealloc)
631 HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
632 return S_OK;
635 static HRESULT
636 serialize_DISPPARAM_ptr(
637 ITypeInfo *tinfo,
638 BOOL writeit,
639 BOOL debugout,
640 BOOL dealloc,
641 TYPEDESC *tdesc,
642 DWORD *arg,
643 marshal_state *buf
645 DWORD cookie;
646 HRESULT hres;
647 DISPPARAMS *disp;
648 int i;
650 if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
651 FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
652 return E_FAIL;
655 cookie = *arg ? 0x42424242 : 0x0;
656 if (writeit) {
657 hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
658 if (hres)
659 return hres;
661 if (!*arg) {
662 if (debugout) MESSAGE("<DISPPARAMS NULL>");
663 return S_OK;
665 disp = (DISPPARAMS*)*arg;
666 if (writeit) {
667 hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
668 if (hres)
669 return hres;
671 if (debugout) MESSAGE("D{");
672 for (i=0;i<disp->cArgs;i++) {
673 TYPEDESC vtdesc;
675 vtdesc.vt = VT_VARIANT;
676 serialize_param(
677 tinfo,
678 writeit,
679 debugout,
680 dealloc,
681 &vtdesc,
682 (DWORD*)(disp->rgvarg+i),
685 if (debugout && (i<disp->cArgs-1))
686 MESSAGE(",");
688 if (dealloc)
689 HeapFree(GetProcessHeap(),0,disp->rgvarg);
690 if (writeit) {
691 hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
692 if (hres)
693 return hres;
695 if (debugout) MESSAGE("}{");
696 for (i=0;i<disp->cNamedArgs;i++) {
697 TYPEDESC vtdesc;
699 vtdesc.vt = VT_UINT;
700 serialize_param(
701 tinfo,
702 writeit,
703 debugout,
704 dealloc,
705 &vtdesc,
706 (DWORD*)(disp->rgdispidNamedArgs+i),
709 if (debugout && (i<disp->cNamedArgs-1))
710 MESSAGE(",");
712 if (debugout) MESSAGE("}");
713 if (dealloc) {
714 HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
715 HeapFree(GetProcessHeap(),0,disp);
717 return S_OK;
720 static HRESULT
721 deserialize_param(
722 ITypeInfo *tinfo,
723 BOOL readit,
724 BOOL debugout,
725 BOOL alloc,
726 TYPEDESC *tdesc,
727 DWORD *arg,
728 marshal_state *buf
730 HRESULT hres = S_OK;
732 TRACE("vt %d at %p\n",tdesc->vt,arg);
734 while (1) {
735 switch (tdesc->vt) {
736 case VT_EMPTY:
737 if (debugout) MESSAGE("<empty>");
738 return S_OK;
739 case VT_NULL:
740 if (debugout) MESSAGE("<null>");
741 return S_OK;
742 case VT_VARIANT: {
743 VARIANT *vt = (VARIANT*)arg;
745 if (readit) {
746 DWORD vttype;
747 TYPEDESC tdesc2;
748 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
749 if (hres) {
750 FIXME("vt type not read?\n");
751 return hres;
753 memset(&tdesc2,0,sizeof(tdesc2));
754 tdesc2.vt = vttype;
755 V_VT(vt) = vttype;
756 if (debugout) MESSAGE("Vt(%ld)(",vttype);
757 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);
758 MESSAGE(")");
759 return hres;
760 } else {
761 VariantInit(vt);
762 return S_OK;
765 case VT_ERROR:
766 case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT: case VT_R4:
767 case VT_UI2:
768 case VT_UI1:
769 if (readit) {
770 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
771 if (hres) FIXME("Failed to read integer 4 byte\n");
773 if (debugout) MESSAGE("%lx",*arg);
774 return hres;
775 case VT_BSTR: {
776 WCHAR *str;
777 DWORD len;
779 if (readit) {
780 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
781 if (hres) {
782 FIXME("failed to read bstr klen\n");
783 return hres;
785 if (len == -1) {
786 *arg = 0;
787 if (debugout) MESSAGE("<bstr NULL>");
788 } else {
789 str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
790 hres = xbuf_get(buf,(LPBYTE)str,len);
791 if (hres) {
792 FIXME("Failed to read BSTR.\n");
793 return hres;
795 *arg = (DWORD)SysAllocStringLen(str,len);
796 if (debugout) MESSAGE("%s",debugstr_w(str));
797 HeapFree(GetProcessHeap(),0,str);
799 } else {
800 *arg = 0;
802 return S_OK;
804 case VT_PTR: {
805 DWORD cookie;
806 BOOL derefhere = 0;
808 derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
810 if (readit) {
811 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
812 if (hres) {
813 FIXME("Failed to load pointer cookie.\n");
814 return hres;
816 if (cookie != 0x42424242) {
817 if (debugout) MESSAGE("NULL");
818 *arg = 0;
819 return S_OK;
821 if (debugout) MESSAGE("*");
823 if (alloc) {
824 if (derefhere)
825 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
827 if (derefhere)
828 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
829 else
830 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
832 case VT_UNKNOWN:
833 /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
834 if (alloc)
835 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
836 hres = S_OK;
837 if (readit)
838 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
839 if (debugout)
840 MESSAGE("unk(%p)",arg);
841 return hres;
842 case VT_DISPATCH:
843 hres = S_OK;
844 if (readit)
845 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
846 if (debugout)
847 MESSAGE("idisp(%p)",arg);
848 return hres;
849 case VT_VOID:
850 if (debugout) MESSAGE("<void>");
851 return S_OK;
852 case VT_USERDEFINED: {
853 ITypeInfo *tinfo2;
854 TYPEATTR *tattr;
856 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
857 if (hres) {
858 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
859 return hres;
861 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
862 if (hres) {
863 FIXME("Could not get typeattr in VT_USERDEFINED.\n");
864 } else {
865 if (alloc)
866 *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
867 switch (tattr->typekind) {
868 case TKIND_DISPATCH:
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 ERR("Unhandled typekind %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;