shlwapi/tests: Link directly to Url*() functions.
[wine.git] / dlls / rpcrt4 / ndr_typelib.c
blobf1f25885b75684479e91fd5b1908bb51a2d2e179
1 /*
2 * Type library proxy/stub implementation
4 * Copyright 2018 Zebediah Figura
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
23 #define COBJMACROS
24 #include "oaidl.h"
25 #define USE_STUBLESS_PROXY
26 #include "rpcproxy.h"
27 #include "ndrtypes.h"
28 #include "wine/debug.h"
29 #include "wine/heap.h"
31 #include "cpsf.h"
32 #include "initguid.h"
33 #include "ndr_types.h"
34 #include "ndr_stubless.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
39 size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack);
41 #define WRITE_CHAR(str, len, val) \
42 do { if ((str)) (str)[(len)] = (val); (len)++; } while (0)
43 #define WRITE_SHORT(str, len, val) \
44 do { if ((str)) *((short *)((str) + (len))) = (val); (len) += 2; } while (0)
45 #define WRITE_INT(str, len, val) \
46 do { if ((str)) *((int *)((str) + (len))) = (val); (len) += 4; } while (0)
48 extern const ExtendedProxyFileInfo ndr_types_ProxyFileInfo;
50 static const MIDL_STUBLESS_PROXY_INFO *get_ndr_types_proxy_info(void)
52 return ndr_types_ProxyFileInfo.pProxyVtblList[0]->header.pStublessProxyInfo;
55 static const NDR_PARAM_OIF *get_ndr_types_params( unsigned int *nb_params )
57 const MIDL_STUBLESS_PROXY_INFO *proxy = get_ndr_types_proxy_info();
58 const unsigned char *format = proxy->ProcFormatString + proxy->FormatStringOffset[3];
59 const NDR_PROC_HEADER *proc = (const NDR_PROC_HEADER *)format;
60 const NDR_PROC_PARTIAL_OIF_HEADER *header;
62 if (proc->Oi_flags & Oi_HAS_RPCFLAGS)
63 format += sizeof(NDR_PROC_HEADER_RPC);
64 else
65 format += sizeof(NDR_PROC_HEADER);
67 header = (const NDR_PROC_PARTIAL_OIF_HEADER *)format;
68 format += sizeof(*header);
69 if (header->Oi2Flags.HasExtensions)
71 const NDR_PROC_HEADER_EXTS *ext = (const NDR_PROC_HEADER_EXTS *)format;
72 format += ext->Size;
74 *nb_params = header->number_of_params;
75 return (const NDR_PARAM_OIF *)format;
78 static unsigned short get_tfs_offset( int param )
80 unsigned int nb_params;
81 const NDR_PARAM_OIF *params = get_ndr_types_params( &nb_params );
83 assert( param < nb_params );
84 return params[param].u.type_offset;
87 static const unsigned char *get_type_format_string( size_t *size )
89 unsigned int nb_params;
90 const NDR_PARAM_OIF *params = get_ndr_types_params( &nb_params );
92 *size = params[nb_params - 1].u.type_offset;
93 return get_ndr_types_proxy_info()->pStubDesc->pFormatTypes;
96 static unsigned short write_oleaut_tfs(VARTYPE vt)
98 switch (vt)
100 case VT_BSTR: return get_tfs_offset( 0 );
101 case VT_UNKNOWN: return get_tfs_offset( 1 );
102 case VT_DISPATCH: return get_tfs_offset( 2 );
103 case VT_VARIANT: return get_tfs_offset( 3 );
104 case VT_SAFEARRAY: return get_tfs_offset( 4 );
106 return 0;
109 static unsigned char get_basetype(ITypeInfo *typeinfo, TYPEDESC *desc)
111 ITypeInfo *refinfo;
112 unsigned char ret;
113 TYPEATTR *attr;
115 switch (desc->vt)
117 case VT_I1: return FC_SMALL;
118 case VT_BOOL:
119 case VT_I2: return FC_SHORT;
120 case VT_INT:
121 case VT_ERROR:
122 case VT_HRESULT:
123 case VT_I4: return FC_LONG;
124 case VT_I8:
125 case VT_UI8: return FC_HYPER;
126 case VT_UI1: return FC_USMALL;
127 case VT_UI2: return FC_USHORT;
128 case VT_UINT:
129 case VT_UI4: return FC_ULONG;
130 case VT_R4: return FC_FLOAT;
131 case VT_DATE:
132 case VT_R8: return FC_DOUBLE;
133 case VT_USERDEFINED:
134 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
135 ITypeInfo_GetTypeAttr(refinfo, &attr);
136 if (attr->typekind == TKIND_ENUM)
137 ret = FC_ENUM32;
138 else if (attr->typekind == TKIND_ALIAS)
139 ret = get_basetype(refinfo, &attr->tdescAlias);
140 else
141 ret = 0;
142 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
143 ITypeInfo_Release(refinfo);
144 return ret;
145 default: return 0;
149 static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc)
151 switch (desc->vt)
153 case VT_I1:
154 case VT_UI1:
155 return 1;
156 case VT_I2:
157 case VT_UI2:
158 case VT_BOOL:
159 return 2;
160 case VT_I4:
161 case VT_UI4:
162 case VT_R4:
163 case VT_INT:
164 case VT_UINT:
165 case VT_ERROR:
166 case VT_HRESULT:
167 return 4;
168 case VT_I8:
169 case VT_UI8:
170 case VT_R8:
171 case VT_DATE:
172 return 8;
173 case VT_BSTR:
174 case VT_SAFEARRAY:
175 case VT_PTR:
176 case VT_UNKNOWN:
177 case VT_DISPATCH:
178 return sizeof(void *);
179 case VT_VARIANT:
180 return sizeof(VARIANT);
181 case VT_CARRAY:
183 unsigned int size = type_memsize(typeinfo, &desc->lpadesc->tdescElem);
184 unsigned int i;
185 for (i = 0; i < desc->lpadesc->cDims; i++)
186 size *= desc->lpadesc->rgbounds[i].cElements;
187 return size;
189 case VT_USERDEFINED:
191 unsigned int size = 0;
192 ITypeInfo *refinfo;
193 TYPEATTR *attr;
195 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
196 ITypeInfo_GetTypeAttr(refinfo, &attr);
197 size = attr->cbSizeInstance;
198 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
199 ITypeInfo_Release(refinfo);
200 return size;
202 default:
203 FIXME("unhandled type %u\n", desc->vt);
204 return 0;
208 static BOOL type_pointer_is_iface(ITypeInfo *typeinfo, TYPEDESC *tdesc)
210 ITypeInfo *refinfo;
211 BOOL ret = FALSE;
212 TYPEATTR *attr;
214 if (tdesc->vt == VT_USERDEFINED)
216 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
217 ITypeInfo_GetTypeAttr(refinfo, &attr);
219 if (attr->typekind == TKIND_INTERFACE
220 || attr->typekind == TKIND_DISPATCH
221 || attr->typekind == TKIND_COCLASS)
222 ret = TRUE;
223 else if (attr->typekind == TKIND_ALIAS)
224 ret = type_pointer_is_iface(refinfo, &attr->tdescAlias);
226 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
227 ITypeInfo_Release(refinfo);
230 return ret;
233 static unsigned char get_array_fc(ITypeInfo *typeinfo, TYPEDESC *desc);
234 static unsigned char get_struct_fc(ITypeInfo *typeinfo, TYPEATTR *attr);
236 static unsigned char get_struct_member_fc(ITypeInfo *typeinfo, TYPEDESC *tdesc)
238 unsigned char fc;
239 ITypeInfo *refinfo;
240 TYPEATTR *attr;
242 switch (tdesc->vt)
244 case VT_BSTR:
245 case VT_SAFEARRAY:
246 return (sizeof(void *) == 4) ? FC_PSTRUCT : FC_BOGUS_STRUCT;
247 case VT_CY:
248 return FC_STRUCT;
249 case VT_VARIANT:
250 case VT_UNKNOWN:
251 case VT_DISPATCH:
252 return FC_BOGUS_STRUCT;
253 case VT_CARRAY:
254 if (get_array_fc(typeinfo, &tdesc->lpadesc->tdescElem) == FC_BOGUS_ARRAY)
255 return FC_BOGUS_STRUCT;
256 return FC_STRUCT;
257 case VT_PTR:
258 if (type_pointer_is_iface(typeinfo, tdesc))
259 fc = FC_BOGUS_STRUCT;
260 else
261 fc = (sizeof(void *) == 4) ? FC_PSTRUCT : FC_BOGUS_STRUCT;
262 break;
263 case VT_USERDEFINED:
264 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
265 ITypeInfo_GetTypeAttr(refinfo, &attr);
267 switch (attr->typekind)
269 case TKIND_ENUM:
270 fc = FC_STRUCT;
271 break;
272 case TKIND_RECORD:
273 fc = get_struct_fc(refinfo, attr);
274 break;
275 case TKIND_INTERFACE:
276 case TKIND_DISPATCH:
277 case TKIND_COCLASS:
278 fc = FC_BOGUS_STRUCT;
279 break;
280 case TKIND_ALIAS:
281 fc = get_struct_member_fc(refinfo, &attr->tdescAlias);
282 break;
283 default:
284 FIXME("Unhandled kind %#x.\n", attr->typekind);
285 fc = FC_BOGUS_STRUCT;
286 break;
289 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
290 ITypeInfo_Release(refinfo);
291 break;
292 default:
293 if (get_basetype(typeinfo, tdesc))
294 return FC_STRUCT;
295 else
297 FIXME("Unhandled type %u.\n", tdesc->vt);
298 return FC_BOGUS_STRUCT;
302 return fc;
305 static unsigned char get_struct_fc(ITypeInfo *typeinfo, TYPEATTR *attr)
307 unsigned char fc = FC_STRUCT, member_fc;
308 VARDESC *desc;
309 WORD i;
311 for (i = 0; i < attr->cVars; i++)
313 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
315 member_fc = get_struct_member_fc(typeinfo, &desc->elemdescVar.tdesc);
316 if (member_fc == FC_BOGUS_STRUCT)
317 fc = FC_BOGUS_STRUCT;
318 else if (member_fc == FC_PSTRUCT && fc != FC_BOGUS_STRUCT)
319 fc = FC_PSTRUCT;
321 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
324 return fc;
327 static unsigned char get_array_fc(ITypeInfo *typeinfo, TYPEDESC *desc)
329 switch (desc->vt)
331 case VT_CY:
332 return FC_LGFARRAY;
333 case VT_CARRAY:
334 return get_array_fc(typeinfo, &desc->lpadesc->tdescElem);
335 case VT_USERDEFINED:
337 ITypeInfo *refinfo;
338 TYPEATTR *attr;
339 unsigned char fc;
341 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
342 ITypeInfo_GetTypeAttr(refinfo, &attr);
344 if (attr->typekind == TKIND_ENUM)
345 fc = FC_LGFARRAY;
346 else if (attr->typekind == TKIND_RECORD && get_struct_fc(refinfo, attr) == FC_STRUCT)
347 fc = FC_LGFARRAY;
348 else if (attr->typekind == TKIND_ALIAS)
349 fc = get_array_fc(refinfo, &attr->tdescAlias);
350 else
351 fc = FC_BOGUS_ARRAY;
353 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
354 ITypeInfo_Release(refinfo);
356 return fc;
358 default:
359 return get_basetype(typeinfo, desc) ? FC_LGFARRAY : FC_BOGUS_ARRAY;
363 static BOOL type_is_non_iface_pointer(ITypeInfo *typeinfo, TYPEDESC *desc)
365 if (desc->vt == VT_PTR)
366 return !type_pointer_is_iface(typeinfo, desc->lptdesc);
367 else if (desc->vt == VT_USERDEFINED)
369 ITypeInfo *refinfo;
370 TYPEATTR *attr;
371 BOOL ret;
373 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
374 ITypeInfo_GetTypeAttr(refinfo, &attr);
376 if (attr->typekind == TKIND_ALIAS)
377 ret = type_is_non_iface_pointer(refinfo, &attr->tdescAlias);
378 else
379 ret = FALSE;
381 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
382 ITypeInfo_Release(refinfo);
384 return ret;
386 else
387 return FALSE;
390 static void write_struct_members(ITypeInfo *typeinfo, unsigned char *str,
391 size_t *len, TYPEATTR *attr)
393 unsigned int struct_offset = 0;
394 unsigned char basetype;
395 TYPEDESC *tdesc;
396 VARDESC *desc;
397 WORD i;
399 for (i = 0; i < attr->cVars; i++)
401 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
402 tdesc = &desc->elemdescVar.tdesc;
404 /* This may not match the intended alignment, but we don't have enough
405 * information to determine that. This should always give the correct
406 * layout. */
407 if ((struct_offset & 7) && !(desc->oInst & 7))
408 WRITE_CHAR(str, *len, FC_ALIGNM8);
409 else if ((struct_offset & 3) && !(desc->oInst & 3))
410 WRITE_CHAR(str, *len, FC_ALIGNM4);
411 else if ((struct_offset & 1) && !(desc->oInst & 1))
412 WRITE_CHAR(str, *len, FC_ALIGNM2);
413 struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
415 if ((basetype = get_basetype(typeinfo, tdesc)))
416 WRITE_CHAR(str, *len, basetype);
417 else if (type_is_non_iface_pointer(typeinfo, tdesc))
418 WRITE_CHAR(str, *len, FC_POINTER);
419 else
421 WRITE_CHAR(str, *len, FC_EMBEDDED_COMPLEX);
422 WRITE_CHAR(str, *len, 0);
423 WRITE_SHORT(str, *len, 0);
426 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
428 if (!(*len & 1))
429 WRITE_CHAR (str, *len, FC_PAD);
430 WRITE_CHAR (str, *len, FC_END);
433 static void write_simple_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
434 size_t *len, TYPEATTR *attr)
436 write_struct_members(typeinfo, str, len, attr);
439 static BOOL type_needs_pointer_deref(ITypeInfo *typeinfo, TYPEDESC *desc)
441 if (desc->vt == VT_PTR || desc->vt == VT_UNKNOWN || desc->vt == VT_DISPATCH)
442 return TRUE;
443 else if (desc->vt == VT_USERDEFINED)
445 ITypeInfo *refinfo;
446 BOOL ret = FALSE;
447 TYPEATTR *attr;
449 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
450 ITypeInfo_GetTypeAttr(refinfo, &attr);
452 if (attr->typekind == TKIND_ALIAS)
453 ret = type_needs_pointer_deref(refinfo, &attr->tdescAlias);
455 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
456 ITypeInfo_Release(refinfo);
458 return ret;
460 else
461 return FALSE;
464 static void write_complex_struct_pointer_layout(ITypeInfo *typeinfo,
465 TYPEDESC *desc, unsigned char *str, size_t *len)
467 unsigned char basetype;
469 if (desc->vt == VT_PTR && !type_pointer_is_iface(typeinfo, desc->lptdesc))
471 WRITE_CHAR(str, *len, FC_UP);
472 if ((basetype = get_basetype(typeinfo, desc->lptdesc)))
474 WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
475 WRITE_CHAR(str, *len, basetype);
476 WRITE_CHAR(str, *len, FC_PAD);
478 else
480 if (type_needs_pointer_deref(typeinfo, desc->lptdesc))
481 WRITE_CHAR(str, *len, FC_POINTER_DEREF);
482 else
483 WRITE_CHAR(str, *len, 0);
484 WRITE_SHORT(str, *len, 0);
487 else if (desc->vt == VT_USERDEFINED)
489 ITypeInfo *refinfo;
490 TYPEATTR *attr;
492 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
493 ITypeInfo_GetTypeAttr(refinfo, &attr);
495 if (attr->typekind == TKIND_ALIAS)
496 write_complex_struct_pointer_layout(refinfo, &attr->tdescAlias, str, len);
498 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
499 ITypeInfo_Release(refinfo);
503 static size_t write_complex_struct_pointer_ref(ITypeInfo *typeinfo,
504 TYPEDESC *desc, unsigned char *str, size_t *len)
506 if (desc->vt == VT_PTR && !type_pointer_is_iface(typeinfo, desc->lptdesc)
507 && !get_basetype(typeinfo, desc->lptdesc))
509 return write_type_tfs(typeinfo, str, len, desc->lptdesc, FALSE, FALSE);
511 else if (desc->vt == VT_USERDEFINED)
513 ITypeInfo *refinfo;
514 TYPEATTR *attr;
515 size_t ret = 0;
517 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
518 ITypeInfo_GetTypeAttr(refinfo, &attr);
520 if (attr->typekind == TKIND_ALIAS)
521 ret = write_complex_struct_pointer_ref(refinfo, &attr->tdescAlias, str, len);
523 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
524 ITypeInfo_Release(refinfo);
526 return ret;
529 return 0;
532 static void write_complex_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
533 size_t *len, TYPEATTR *attr)
535 size_t pointer_layout_offset, pointer_layout, member_layout, ref;
536 unsigned int struct_offset = 0;
537 TYPEDESC *tdesc;
538 VARDESC *desc;
539 WORD i;
541 WRITE_SHORT(str, *len, 0); /* conformant array description */
542 pointer_layout_offset = *len;
543 WRITE_SHORT(str, *len, 0); /* pointer layout; will be filled in later */
544 member_layout = *len;
546 /* First pass: write the struct members and pointer layout, but do not yet
547 * write the offsets for embedded complexes and pointer refs. These must be
548 * handled after we write the whole struct description, since it must be
549 * contiguous. */
551 write_struct_members(typeinfo, str, len, attr);
553 pointer_layout = *len;
554 if (str) *((short *)(str + pointer_layout_offset)) = pointer_layout - pointer_layout_offset;
556 for (i = 0; i < attr->cVars; i++)
558 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
559 write_complex_struct_pointer_layout(typeinfo, &desc->elemdescVar.tdesc, str, len);
560 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
563 /* Second pass: write types for embedded complexes and non-simple pointers. */
565 struct_offset = 0;
567 for (i = 0; i < attr->cVars; i++)
569 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
570 tdesc = &desc->elemdescVar.tdesc;
572 if (struct_offset != desc->oInst)
573 member_layout++; /* alignment directive */
574 struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
576 if (get_basetype(typeinfo, tdesc))
577 member_layout++;
578 else if (type_is_non_iface_pointer(typeinfo, tdesc))
580 member_layout++;
581 if ((ref = write_complex_struct_pointer_ref(typeinfo, tdesc, str, len)))
583 if (str) *((short *)(str + pointer_layout + 2)) = ref - (pointer_layout + 2);
585 pointer_layout += 4;
587 else
589 ref = write_type_tfs(typeinfo, str, len, tdesc, FALSE, FALSE);
590 if (str) *((short *)(str + member_layout + 2)) = ref - (member_layout + 2);
591 member_layout += 4;
594 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
598 static size_t write_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
599 size_t *len, TYPEATTR *attr)
601 unsigned char fc = get_struct_fc(typeinfo, attr);
602 size_t off = *len;
604 /* For the sake of simplicity, write pointer structs as complex structs. */
605 if (fc == FC_PSTRUCT)
606 fc = FC_BOGUS_STRUCT;
608 WRITE_CHAR (str, *len, fc);
609 WRITE_CHAR (str, *len, attr->cbAlignment - 1);
610 WRITE_SHORT(str, *len, attr->cbSizeInstance);
612 if (fc == FC_STRUCT)
613 write_simple_struct_tfs(typeinfo, str, len, attr);
614 else if (fc == FC_BOGUS_STRUCT)
615 write_complex_struct_tfs(typeinfo, str, len, attr);
617 return off;
620 static size_t write_array_tfs(ITypeInfo *typeinfo, unsigned char *str,
621 size_t *len, ARRAYDESC *desc)
623 unsigned char fc = get_array_fc(typeinfo, &desc->tdescElem);
624 unsigned char basetype;
625 size_t ref = 0, off;
626 ULONG size = 1;
627 USHORT i;
629 if (!(basetype = get_basetype(typeinfo, &desc->tdescElem)))
630 ref = write_type_tfs(typeinfo, str, len, &desc->tdescElem, FALSE, FALSE);
632 /* In theory arrays should be nested, but there's no reason not to marshal
633 * [x][y] as [x*y]. */
634 for (i = 0; i < desc->cDims; i++) size *= desc->rgbounds[i].cElements;
636 off = *len;
638 WRITE_CHAR(str, *len, fc);
639 WRITE_CHAR(str, *len, 0);
640 if (fc == FC_BOGUS_ARRAY)
642 WRITE_SHORT(str, *len, size);
643 WRITE_INT(str, *len, 0xffffffff); /* conformance */
644 WRITE_INT(str, *len, 0xffffffff); /* variance */
646 else
648 size *= type_memsize(typeinfo, &desc->tdescElem);
649 WRITE_INT(str, *len, size);
652 if (basetype)
653 WRITE_CHAR(str, *len, basetype);
654 else
656 WRITE_CHAR (str, *len, FC_EMBEDDED_COMPLEX);
657 WRITE_CHAR (str, *len, 0);
658 WRITE_SHORT(str, *len, ref - *len);
659 WRITE_CHAR (str, *len, FC_PAD);
661 WRITE_CHAR(str, *len, FC_END);
663 return off;
666 static size_t write_ip_tfs(unsigned char *str, size_t *len, const GUID *iid)
668 size_t off = *len;
670 if (str)
672 str[*len] = FC_IP;
673 str[*len+1] = FC_CONSTANT_IID;
674 memcpy(str + *len + 2, iid, sizeof(*iid));
676 *len += 2 + sizeof(*iid);
678 return off;
681 static void get_default_iface(ITypeInfo *typeinfo, WORD count, GUID *iid)
683 ITypeInfo *refinfo;
684 HREFTYPE reftype;
685 TYPEATTR *attr;
686 int flags, i;
688 for (i = 0; i < count; ++i)
690 ITypeInfo_GetImplTypeFlags(typeinfo, i, &flags);
691 if (flags & IMPLTYPEFLAG_FDEFAULT)
692 break;
695 /* If no interface was explicitly marked default, choose the first one. */
696 if (i == count)
697 i = 0;
699 ITypeInfo_GetRefTypeOfImplType(typeinfo, i, &reftype);
700 ITypeInfo_GetRefTypeInfo(typeinfo, reftype, &refinfo);
701 ITypeInfo_GetTypeAttr(refinfo, &attr);
702 *iid = attr->guid;
703 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
704 ITypeInfo_Release(refinfo);
707 static size_t write_pointer_tfs(ITypeInfo *typeinfo, unsigned char *str,
708 size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack)
710 unsigned char basetype, flags = 0;
711 size_t ref, off = *len;
712 ITypeInfo *refinfo;
713 TYPEATTR *attr;
714 GUID guid;
716 if (desc->vt == VT_USERDEFINED)
718 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
719 ITypeInfo_GetTypeAttr(refinfo, &attr);
721 switch (attr->typekind)
723 case TKIND_ENUM:
724 assert(!toplevel); /* toplevel base-type pointers should use IsSimpleRef */
725 WRITE_CHAR(str, *len, FC_UP);
726 WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
727 WRITE_CHAR(str, *len, FC_ENUM32);
728 WRITE_CHAR(str, *len, FC_PAD);
729 break;
730 case TKIND_RECORD:
731 assert(!toplevel); /* toplevel struct pointers should use IsSimpleRef */
732 ref = write_struct_tfs(refinfo, str, len, attr);
733 off = *len;
734 WRITE_CHAR (str, *len, FC_UP);
735 WRITE_CHAR (str, *len, 0);
736 WRITE_SHORT(str, *len, ref - *len);
737 break;
738 case TKIND_INTERFACE:
739 case TKIND_DISPATCH:
740 write_ip_tfs(str, len, &attr->guid);
741 break;
742 case TKIND_COCLASS:
743 get_default_iface(refinfo, attr->cImplTypes, &guid);
744 write_ip_tfs(str, len, &guid);
745 break;
746 case TKIND_ALIAS:
747 off = write_pointer_tfs(refinfo, str, len, &attr->tdescAlias, toplevel, onstack);
748 break;
749 default:
750 FIXME("unhandled kind %#x\n", attr->typekind);
751 WRITE_SHORT(str, *len, 0);
752 break;
755 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
756 ITypeInfo_Release(refinfo);
758 else if ((basetype = get_basetype(typeinfo, desc)))
760 assert(!toplevel); /* toplevel base-type pointers should use IsSimpleRef */
761 WRITE_CHAR(str, *len, FC_UP);
762 WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
763 WRITE_CHAR(str, *len, basetype);
764 WRITE_CHAR(str, *len, FC_PAD);
766 else
768 ref = write_type_tfs(typeinfo, str, len, desc, FALSE, FALSE);
770 if (onstack) flags |= FC_ALLOCED_ON_STACK;
771 if (desc->vt == VT_PTR || desc->vt == VT_UNKNOWN || desc->vt == VT_DISPATCH)
772 flags |= FC_POINTER_DEREF;
774 off = *len;
776 WRITE_CHAR (str, *len, toplevel ? FC_RP : FC_UP);
777 WRITE_CHAR (str, *len, flags);
778 WRITE_SHORT(str, *len, ref - *len);
781 return off;
784 static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
785 size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack)
787 ITypeInfo *refinfo;
788 TYPEATTR *attr;
789 size_t off;
790 GUID guid;
792 TRACE("vt %d%s\n", desc->vt, toplevel ? " (toplevel)" : "");
794 if ((off = write_oleaut_tfs(desc->vt)))
795 return off;
797 switch (desc->vt)
799 case VT_PTR:
800 return write_pointer_tfs(typeinfo, str, len, desc->lptdesc, toplevel, onstack);
801 case VT_CARRAY:
802 return write_array_tfs(typeinfo, str, len, desc->lpadesc);
803 case VT_USERDEFINED:
804 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
805 ITypeInfo_GetTypeAttr(refinfo, &attr);
807 switch (attr->typekind)
809 case TKIND_RECORD:
810 off = write_struct_tfs(refinfo, str, len, attr);
811 break;
812 case TKIND_INTERFACE:
813 case TKIND_DISPATCH:
814 /* These are treated as if they were interface pointers. */
815 off = *len;
816 write_ip_tfs(str, len, &attr->guid);
817 break;
818 case TKIND_COCLASS:
819 off = *len;
820 get_default_iface(refinfo, attr->cImplTypes, &guid);
821 write_ip_tfs(str, len, &guid);
822 break;
823 case TKIND_ALIAS:
824 off = write_type_tfs(refinfo, str, len, &attr->tdescAlias, toplevel, onstack);
825 break;
826 default:
827 FIXME("unhandled kind %u\n", attr->typekind);
828 off = *len;
829 WRITE_SHORT(str, *len, 0);
830 break;
833 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
834 ITypeInfo_Release(refinfo);
835 break;
836 default:
837 /* base types are always embedded directly */
838 assert(!get_basetype(typeinfo, desc));
839 FIXME("unhandled type %u\n", desc->vt);
840 off = *len;
841 WRITE_SHORT(str, *len, 0);
842 break;
845 return off;
848 static unsigned short get_stack_size(ITypeInfo *typeinfo, TYPEDESC *desc)
850 #if defined(__i386__) || defined(__arm__)
851 if (desc->vt == VT_CARRAY)
852 return sizeof(void *);
853 return (type_memsize(typeinfo, desc) + 3) & ~3;
854 #else
855 return sizeof(void *);
856 #endif
859 static const unsigned short MustSize = 0x0001;
860 static const unsigned short MustFree = 0x0002;
861 static const unsigned short IsIn = 0x0008;
862 static const unsigned short IsOut = 0x0010;
863 static const unsigned short IsReturn = 0x0020;
864 static const unsigned short IsBasetype = 0x0040;
865 static const unsigned short IsByValue = 0x0080;
866 static const unsigned short IsSimpleRef = 0x0100;
868 static HRESULT get_param_pointer_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
869 int is_out, unsigned short *server_size, unsigned short *flags,
870 unsigned char *basetype, TYPEDESC **tfs_tdesc)
872 ITypeInfo *refinfo;
873 HRESULT hr = S_OK;
874 TYPEATTR *attr;
876 switch (tdesc->vt)
878 case VT_UNKNOWN:
879 case VT_DISPATCH:
880 *flags |= MustFree;
881 if (is_in && is_out)
882 *server_size = sizeof(void *);
883 break;
884 case VT_PTR:
885 *flags |= MustFree;
886 if (type_pointer_is_iface(typeinfo, tdesc->lptdesc))
888 if (is_in && is_out)
889 *server_size = sizeof(void *);
891 else
892 *server_size = sizeof(void *);
893 break;
894 case VT_CARRAY:
895 *flags |= IsSimpleRef | MustFree;
896 *server_size = type_memsize(typeinfo, tdesc);
897 *tfs_tdesc = tdesc;
898 break;
899 case VT_USERDEFINED:
900 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
901 ITypeInfo_GetTypeAttr(refinfo, &attr);
903 switch (attr->typekind)
905 case TKIND_ENUM:
906 *flags |= IsSimpleRef | IsBasetype;
907 if (!is_in && is_out)
908 *server_size = sizeof(void *);
909 *basetype = FC_ENUM32;
910 break;
911 case TKIND_RECORD:
912 *flags |= IsSimpleRef | MustFree;
913 if (!is_in && is_out)
914 *server_size = attr->cbSizeInstance;
915 *tfs_tdesc = tdesc;
916 break;
917 case TKIND_INTERFACE:
918 case TKIND_DISPATCH:
919 case TKIND_COCLASS:
920 *flags |= MustFree;
921 break;
922 case TKIND_ALIAS:
923 hr = get_param_pointer_info(refinfo, &attr->tdescAlias, is_in,
924 is_out, server_size, flags, basetype, tfs_tdesc);
925 break;
926 default:
927 FIXME("unhandled kind %#x\n", attr->typekind);
928 hr = E_NOTIMPL;
929 break;
932 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
933 ITypeInfo_Release(refinfo);
934 break;
935 default:
936 *flags |= IsSimpleRef;
937 *tfs_tdesc = tdesc;
938 if (!is_in && is_out)
939 *server_size = type_memsize(typeinfo, tdesc);
940 if ((*basetype = get_basetype(typeinfo, tdesc)))
941 *flags |= IsBasetype;
942 else
943 *flags |= MustFree;
944 break;
947 return hr;
950 static HRESULT get_param_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
951 int is_out, unsigned short *server_size, unsigned short *flags,
952 unsigned char *basetype, TYPEDESC **tfs_tdesc)
954 ITypeInfo *refinfo;
955 HRESULT hr = S_OK;
956 TYPEATTR *attr;
958 *server_size = 0;
959 *flags = MustSize;
960 *basetype = 0;
961 *tfs_tdesc = tdesc;
963 TRACE("vt %u\n", tdesc->vt);
965 switch (tdesc->vt)
967 case VT_VARIANT:
968 #if !defined(__i386__) && !defined(__arm__)
969 *flags |= IsSimpleRef | MustFree;
970 break;
971 #endif
972 /* otherwise fall through */
973 case VT_BSTR:
974 case VT_SAFEARRAY:
975 case VT_CY:
976 *flags |= IsByValue | MustFree;
977 break;
978 case VT_UNKNOWN:
979 case VT_DISPATCH:
980 case VT_CARRAY:
981 *flags |= MustFree;
982 break;
983 case VT_PTR:
984 return get_param_pointer_info(typeinfo, tdesc->lptdesc, is_in, is_out,
985 server_size, flags, basetype, tfs_tdesc);
986 case VT_USERDEFINED:
987 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
988 ITypeInfo_GetTypeAttr(refinfo, &attr);
990 switch (attr->typekind)
992 case TKIND_ENUM:
993 *flags |= IsBasetype;
994 *basetype = FC_ENUM32;
995 break;
996 case TKIND_RECORD:
997 #if defined(__i386__) || defined(__arm__)
998 *flags |= IsByValue | MustFree;
999 #else
1000 if (attr->cbSizeInstance <= 8)
1001 *flags |= IsByValue | MustFree;
1002 else
1003 *flags |= IsSimpleRef | MustFree;
1004 #endif
1005 break;
1006 case TKIND_ALIAS:
1007 hr = get_param_info(refinfo, &attr->tdescAlias, is_in, is_out,
1008 server_size, flags, basetype, tfs_tdesc);
1009 break;
1011 case TKIND_INTERFACE:
1012 case TKIND_DISPATCH:
1013 case TKIND_COCLASS:
1014 /* These are treated as if they were interface pointers. */
1015 *flags |= MustFree;
1016 break;
1018 default:
1019 FIXME("unhandled kind %#x\n", attr->typekind);
1020 hr = E_NOTIMPL;
1021 break;
1024 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
1025 ITypeInfo_Release(refinfo);
1026 break;
1027 default:
1028 if ((*basetype = get_basetype(typeinfo, tdesc)))
1029 *flags |= IsBasetype;
1030 else
1032 FIXME("unhandled type %u\n", tdesc->vt);
1033 return E_NOTIMPL;
1035 break;
1038 return hr;
1041 static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
1042 size_t *typelen, unsigned char *proc, size_t *proclen, ELEMDESC *desc,
1043 BOOL is_return, unsigned short *stack_offset)
1045 USHORT param_flags = desc->paramdesc.wParamFlags;
1046 TYPEDESC *tdesc = &desc->tdesc, *tfs_tdesc;
1047 unsigned short server_size;
1048 unsigned short stack_size = get_stack_size(typeinfo, tdesc);
1049 unsigned char basetype;
1050 unsigned short flags;
1051 int is_in, is_out;
1052 size_t off = 0;
1053 HRESULT hr;
1055 is_out = param_flags & PARAMFLAG_FOUT;
1056 is_in = (param_flags & PARAMFLAG_FIN) || (!is_out && !is_return);
1058 hr = get_param_info(typeinfo, tdesc, is_in, is_out, &server_size, &flags,
1059 &basetype, &tfs_tdesc);
1061 if (is_in) flags |= IsIn;
1062 if (is_out) flags |= IsOut;
1063 if (is_return) flags |= IsOut | IsReturn;
1065 server_size = (server_size + 7) / 8;
1066 if (server_size >= 8) server_size = 0;
1067 flags |= server_size << 13;
1069 if (!basetype)
1070 off = write_type_tfs(typeinfo, type, typelen, tfs_tdesc, TRUE, server_size != 0);
1072 if (SUCCEEDED(hr))
1074 WRITE_SHORT(proc, *proclen, flags);
1075 WRITE_SHORT(proc, *proclen, *stack_offset);
1076 WRITE_SHORT(proc, *proclen, basetype ? basetype : off);
1078 *stack_offset += stack_size;
1081 return hr;
1084 static void write_proc_func_header(ITypeInfo *typeinfo, FUNCDESC *desc,
1085 WORD proc_idx, unsigned char *proc, size_t *proclen)
1087 unsigned short stack_size = 2 * sizeof(void *); /* This + return */
1088 #ifdef __x86_64__
1089 unsigned short float_mask = 0;
1090 unsigned char basetype;
1091 #endif
1092 WORD param_idx;
1094 WRITE_CHAR (proc, *proclen, FC_AUTO_HANDLE);
1095 WRITE_CHAR (proc, *proclen, Oi_OBJECT_PROC | Oi_OBJ_USE_V2_INTERPRETER);
1096 WRITE_SHORT(proc, *proclen, proc_idx);
1097 for (param_idx = 0; param_idx < desc->cParams; param_idx++)
1098 stack_size += get_stack_size(typeinfo, &desc->lprgelemdescParam[param_idx].tdesc);
1099 WRITE_SHORT(proc, *proclen, stack_size);
1101 WRITE_SHORT(proc, *proclen, 0); /* constant_client_buffer_size */
1102 WRITE_SHORT(proc, *proclen, 0); /* constant_server_buffer_size */
1103 #ifdef __x86_64__
1104 WRITE_CHAR (proc, *proclen, 0x47); /* HasExtensions | HasReturn | ClientMustSize | ServerMustSize */
1105 #else
1106 WRITE_CHAR (proc, *proclen, 0x07); /* HasReturn | ClientMustSize | ServerMustSize */
1107 #endif
1108 WRITE_CHAR (proc, *proclen, desc->cParams + 1); /* incl. return value */
1109 #ifdef __x86_64__
1110 WRITE_CHAR (proc, *proclen, 10); /* extension size */
1111 WRITE_CHAR (proc, *proclen, 0); /* INTERPRETER_OPT_FLAGS2 */
1112 WRITE_SHORT(proc, *proclen, 0); /* ClientCorrHint */
1113 WRITE_SHORT(proc, *proclen, 0); /* ServerCorrHint */
1114 WRITE_SHORT(proc, *proclen, 0); /* NotifyIndex */
1115 for (param_idx = 0; param_idx < desc->cParams && param_idx < 3; param_idx++)
1117 basetype = get_basetype(typeinfo, &desc->lprgelemdescParam[param_idx].tdesc);
1118 if (basetype == FC_FLOAT)
1119 float_mask |= (1 << ((param_idx + 1) * 2));
1120 else if (basetype == FC_DOUBLE)
1121 float_mask |= (2 << ((param_idx + 1) * 2));
1123 WRITE_SHORT(proc, *proclen, float_mask);
1124 #endif
1127 static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, WORD parentfuncs,
1128 unsigned char *type, size_t *typelen, unsigned char *proc,
1129 size_t *proclen, unsigned short *offset)
1131 unsigned short stack_offset;
1132 WORD proc_idx, param_idx;
1133 FUNCDESC *desc;
1134 HRESULT hr;
1136 for (proc_idx = 3; proc_idx < parentfuncs; proc_idx++)
1138 if (offset)
1139 offset[proc_idx - 3] = -1;
1142 for (proc_idx = 0; proc_idx < funcs; proc_idx++)
1144 TRACE("Writing procedure %d.\n", proc_idx);
1146 hr = ITypeInfo_GetFuncDesc(typeinfo, proc_idx, &desc);
1147 if (FAILED(hr)) return hr;
1149 if (offset)
1150 offset[proc_idx + parentfuncs - 3] = *proclen;
1152 write_proc_func_header(typeinfo, desc, proc_idx + parentfuncs, proc, proclen);
1154 stack_offset = sizeof(void *); /* This */
1155 for (param_idx = 0; param_idx < desc->cParams; param_idx++)
1157 TRACE("Writing parameter %d.\n", param_idx);
1158 hr = write_param_fs(typeinfo, type, typelen, proc, proclen,
1159 &desc->lprgelemdescParam[param_idx], FALSE, &stack_offset);
1160 if (FAILED(hr))
1162 ITypeInfo_ReleaseFuncDesc(typeinfo, desc);
1163 return hr;
1167 hr = write_param_fs(typeinfo, type, typelen, proc, proclen,
1168 &desc->elemdescFunc, TRUE, &stack_offset);
1169 ITypeInfo_ReleaseFuncDesc(typeinfo, desc);
1170 if (FAILED(hr)) return hr;
1173 return S_OK;
1176 static HRESULT build_format_strings(ITypeInfo *typeinfo, WORD funcs,
1177 WORD parentfuncs, const unsigned char **type_ret,
1178 const unsigned char **proc_ret, unsigned short **offset_ret)
1180 size_t tfs_size;
1181 const unsigned char *tfs = get_type_format_string( &tfs_size );
1182 size_t typelen = tfs_size, proclen = 0;
1183 unsigned char *type, *proc;
1184 unsigned short *offset;
1185 HRESULT hr;
1187 hr = write_iface_fs(typeinfo, funcs, parentfuncs, NULL, &typelen, NULL, &proclen, NULL);
1188 if (FAILED(hr)) return hr;
1190 type = heap_alloc(typelen);
1191 proc = heap_alloc(proclen);
1192 offset = heap_alloc((parentfuncs + funcs - 3) * sizeof(*offset));
1193 if (!type || !proc || !offset)
1195 ERR("Failed to allocate format strings.\n");
1196 hr = E_OUTOFMEMORY;
1197 goto err;
1200 memcpy(type, tfs, tfs_size);
1201 typelen = tfs_size;
1202 proclen = 0;
1204 hr = write_iface_fs(typeinfo, funcs, parentfuncs, type, &typelen, proc, &proclen, offset);
1205 if (SUCCEEDED(hr))
1207 *type_ret = type;
1208 *proc_ret = proc;
1209 *offset_ret = offset;
1210 return S_OK;
1213 err:
1214 heap_free(type);
1215 heap_free(proc);
1216 heap_free(offset);
1217 return hr;
1220 /* Common helper for Create{Proxy,Stub}FromTypeInfo(). */
1221 static HRESULT get_iface_info(ITypeInfo *typeinfo, WORD *funcs, WORD *parentfuncs,
1222 GUID *parentiid, ITypeInfo **real_typeinfo)
1224 ITypeInfo *parentinfo;
1225 TYPEATTR *typeattr;
1226 ITypeLib *typelib;
1227 TLIBATTR *libattr;
1228 TYPEKIND typekind;
1229 HREFTYPE reftype;
1230 SYSKIND syskind;
1231 HRESULT hr;
1233 /* Dual interfaces report their size to be sizeof(IDispatchVtbl) and their
1234 * implemented type to be IDispatch. We need to retrieve the underlying
1235 * interface to get that information. */
1236 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
1237 if (FAILED(hr))
1238 return hr;
1239 typekind = typeattr->typekind;
1240 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
1241 if (typekind == TKIND_DISPATCH)
1243 hr = ITypeInfo_GetRefTypeOfImplType(typeinfo, -1, &reftype);
1244 if (FAILED(hr))
1245 return hr;
1247 hr = ITypeInfo_GetRefTypeInfo(typeinfo, reftype, real_typeinfo);
1248 if (FAILED(hr))
1249 return hr;
1251 else
1252 ITypeInfo_AddRef(*real_typeinfo = typeinfo);
1254 hr = ITypeInfo_GetContainingTypeLib(*real_typeinfo, &typelib, NULL);
1255 if (FAILED(hr))
1256 goto err;
1258 hr = ITypeLib_GetLibAttr(typelib, &libattr);
1259 if (FAILED(hr))
1261 ITypeLib_Release(typelib);
1262 goto err;
1264 syskind = libattr->syskind;
1265 ITypeLib_ReleaseTLibAttr(typelib, libattr);
1266 ITypeLib_Release(typelib);
1268 hr = ITypeInfo_GetTypeAttr(*real_typeinfo, &typeattr);
1269 if (FAILED(hr))
1270 goto err;
1271 *funcs = typeattr->cFuncs;
1272 *parentfuncs = typeattr->cbSizeVft / (syskind == SYS_WIN64 ? 8 : 4) - *funcs;
1273 ITypeInfo_ReleaseTypeAttr(*real_typeinfo, typeattr);
1275 hr = ITypeInfo_GetRefTypeOfImplType(*real_typeinfo, 0, &reftype);
1276 if (FAILED(hr))
1277 goto err;
1278 hr = ITypeInfo_GetRefTypeInfo(*real_typeinfo, reftype, &parentinfo);
1279 if (FAILED(hr))
1280 goto err;
1282 hr = ITypeInfo_GetTypeAttr(parentinfo, &typeattr);
1283 if (SUCCEEDED(hr))
1285 *parentiid = typeattr->guid;
1286 ITypeInfo_ReleaseTypeAttr(parentinfo, typeattr);
1288 ITypeInfo_Release(parentinfo);
1289 if (SUCCEEDED(hr))
1290 return hr;
1292 err:
1293 ITypeInfo_Release(*real_typeinfo);
1294 return hr;
1297 static void init_stub_desc(MIDL_STUB_DESC *desc)
1299 desc->pfnAllocate = NdrOleAllocate;
1300 desc->pfnFree = NdrOleFree;
1301 desc->Version = 0x50002;
1302 desc->aUserMarshalQuadruple = get_ndr_types_proxy_info()->pStubDesc->aUserMarshalQuadruple;
1303 /* type format string is initialized with proc format string and offset table */
1306 struct typelib_proxy
1308 StdProxyImpl proxy;
1309 IID iid;
1310 MIDL_STUB_DESC stub_desc;
1311 MIDL_STUBLESS_PROXY_INFO proxy_info;
1312 CInterfaceProxyVtbl *proxy_vtbl;
1313 unsigned short *offset_table;
1316 static ULONG WINAPI typelib_proxy_Release(IRpcProxyBuffer *iface)
1318 struct typelib_proxy *proxy = CONTAINING_RECORD(iface, struct typelib_proxy, proxy.IRpcProxyBuffer_iface);
1319 ULONG refcount = InterlockedDecrement(&proxy->proxy.RefCount);
1321 TRACE("(%p) decreasing refs to %d\n", proxy, refcount);
1323 if (!refcount)
1325 if (proxy->proxy.pChannel)
1326 IRpcProxyBuffer_Disconnect(&proxy->proxy.IRpcProxyBuffer_iface);
1327 if (proxy->proxy.base_object)
1328 IUnknown_Release(proxy->proxy.base_object);
1329 if (proxy->proxy.base_proxy)
1330 IRpcProxyBuffer_Release(proxy->proxy.base_proxy);
1331 heap_free((void *)proxy->stub_desc.pFormatTypes);
1332 heap_free((void *)proxy->proxy_info.ProcFormatString);
1333 heap_free(proxy->offset_table);
1334 heap_free(proxy->proxy_vtbl);
1335 heap_free(proxy);
1337 return refcount;
1340 static const IRpcProxyBufferVtbl typelib_proxy_vtbl =
1342 StdProxy_QueryInterface,
1343 StdProxy_AddRef,
1344 typelib_proxy_Release,
1345 StdProxy_Connect,
1346 StdProxy_Disconnect,
1349 static HRESULT typelib_proxy_init(struct typelib_proxy *proxy, IUnknown *outer,
1350 ULONG count, const GUID *parentiid, IRpcProxyBuffer **proxy_buffer, void **out)
1352 if (!fill_stubless_table((IUnknownVtbl *)proxy->proxy_vtbl->Vtbl, count))
1353 return E_OUTOFMEMORY;
1355 if (!outer) outer = (IUnknown *)&proxy->proxy;
1357 proxy->proxy.IRpcProxyBuffer_iface.lpVtbl = &typelib_proxy_vtbl;
1358 proxy->proxy.PVtbl = proxy->proxy_vtbl->Vtbl;
1359 proxy->proxy.RefCount = 1;
1360 proxy->proxy.piid = proxy->proxy_vtbl->header.piid;
1361 proxy->proxy.pUnkOuter = outer;
1363 if (!IsEqualGUID(parentiid, &IID_IUnknown))
1365 HRESULT hr = create_proxy(parentiid, NULL, &proxy->proxy.base_proxy,
1366 (void **)&proxy->proxy.base_object);
1367 if (FAILED(hr)) return hr;
1370 *proxy_buffer = &proxy->proxy.IRpcProxyBuffer_iface;
1371 *out = &proxy->proxy.PVtbl;
1372 IUnknown_AddRef((IUnknown *)*out);
1374 return S_OK;
1377 HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo, IUnknown *outer,
1378 REFIID iid, IRpcProxyBuffer **proxy_buffer, void **out)
1380 struct typelib_proxy *proxy;
1381 WORD funcs, parentfuncs, i;
1382 ITypeInfo *real_typeinfo;
1383 GUID parentiid;
1384 HRESULT hr;
1386 TRACE("typeinfo %p, outer %p, iid %s, proxy_buffer %p, out %p.\n",
1387 typeinfo, outer, debugstr_guid(iid), proxy_buffer, out);
1389 hr = get_iface_info(typeinfo, &funcs, &parentfuncs, &parentiid, &real_typeinfo);
1390 if (FAILED(hr))
1391 return hr;
1393 if (!(proxy = heap_alloc_zero(sizeof(*proxy))))
1395 ERR("Failed to allocate proxy object.\n");
1396 ITypeInfo_Release(real_typeinfo);
1397 return E_OUTOFMEMORY;
1400 init_stub_desc(&proxy->stub_desc);
1401 proxy->proxy_info.pStubDesc = &proxy->stub_desc;
1403 proxy->proxy_vtbl = heap_alloc_zero(sizeof(proxy->proxy_vtbl->header) + (funcs + parentfuncs) * sizeof(void *));
1404 if (!proxy->proxy_vtbl)
1406 ERR("Failed to allocate proxy vtbl.\n");
1407 heap_free(proxy);
1408 ITypeInfo_Release(real_typeinfo);
1409 return E_OUTOFMEMORY;
1411 proxy->proxy_vtbl->header.pStublessProxyInfo = &proxy->proxy_info;
1412 proxy->iid = *iid;
1413 proxy->proxy_vtbl->header.piid = &proxy->iid;
1414 fill_delegated_proxy_table((IUnknownVtbl *)proxy->proxy_vtbl->Vtbl, parentfuncs);
1415 for (i = 0; i < funcs; i++)
1416 proxy->proxy_vtbl->Vtbl[parentfuncs + i] = (void *)-1;
1418 hr = build_format_strings(real_typeinfo, funcs, parentfuncs, &proxy->stub_desc.pFormatTypes,
1419 &proxy->proxy_info.ProcFormatString, &proxy->offset_table);
1420 ITypeInfo_Release(real_typeinfo);
1421 if (FAILED(hr))
1423 heap_free(proxy->proxy_vtbl);
1424 heap_free(proxy);
1425 return hr;
1427 proxy->proxy_info.FormatStringOffset = &proxy->offset_table[-3];
1429 hr = typelib_proxy_init(proxy, outer, funcs + parentfuncs, &parentiid, proxy_buffer, out);
1430 if (FAILED(hr))
1432 heap_free((void *)proxy->stub_desc.pFormatTypes);
1433 heap_free((void *)proxy->proxy_info.ProcFormatString);
1434 heap_free((void *)proxy->offset_table);
1435 heap_free(proxy->proxy_vtbl);
1436 heap_free(proxy);
1439 return hr;
1442 struct typelib_stub
1444 cstdstubbuffer_delegating_t stub;
1445 IID iid;
1446 MIDL_STUB_DESC stub_desc;
1447 MIDL_SERVER_INFO server_info;
1448 CInterfaceStubVtbl stub_vtbl;
1449 unsigned short *offset_table;
1450 PRPC_STUB_FUNCTION *dispatch_table;
1453 static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface)
1455 struct typelib_stub *stub = CONTAINING_RECORD(iface, struct typelib_stub, stub.stub_buffer);
1456 ULONG refcount = InterlockedDecrement(&stub->stub.stub_buffer.RefCount);
1458 TRACE("(%p) decreasing refs to %d\n", stub, refcount);
1460 if (!refcount)
1462 /* test_Release shows that native doesn't call Disconnect here.
1463 We'll leave it in for the time being. */
1464 IRpcStubBuffer_Disconnect(iface);
1466 if (stub->stub.base_stub)
1468 IRpcStubBuffer_Release(stub->stub.base_stub);
1469 release_delegating_vtbl(stub->stub.base_obj);
1470 heap_free(stub->dispatch_table);
1473 heap_free((void *)stub->stub_desc.pFormatTypes);
1474 heap_free((void *)stub->server_info.ProcString);
1475 heap_free(stub->offset_table);
1476 heap_free(stub);
1479 return refcount;
1482 static HRESULT typelib_stub_init(struct typelib_stub *stub, IUnknown *server,
1483 const GUID *parentiid, IRpcStubBuffer **stub_buffer)
1485 HRESULT hr;
1487 hr = IUnknown_QueryInterface(server, stub->stub_vtbl.header.piid,
1488 (void **)&stub->stub.stub_buffer.pvServerObject);
1489 if (FAILED(hr))
1491 WARN("Failed to get interface %s, hr %#x.\n",
1492 debugstr_guid(stub->stub_vtbl.header.piid), hr);
1493 stub->stub.stub_buffer.pvServerObject = server;
1494 IUnknown_AddRef(server);
1497 if (!IsEqualGUID(parentiid, &IID_IUnknown))
1499 stub->stub.base_obj = get_delegating_vtbl(stub->stub_vtbl.header.DispatchTableCount);
1500 hr = create_stub(parentiid, (IUnknown *)&stub->stub.base_obj, &stub->stub.base_stub);
1501 if (FAILED(hr))
1503 release_delegating_vtbl(stub->stub.base_obj);
1504 IUnknown_Release(stub->stub.stub_buffer.pvServerObject);
1505 return hr;
1509 stub->stub.stub_buffer.lpVtbl = &stub->stub_vtbl.Vtbl;
1510 stub->stub.stub_buffer.RefCount = 1;
1512 *stub_buffer = (IRpcStubBuffer *)&stub->stub.stub_buffer;
1513 return S_OK;
1516 HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid,
1517 IUnknown *server, IRpcStubBuffer **stub_buffer)
1519 WORD funcs, parentfuncs, i;
1520 struct typelib_stub *stub;
1521 ITypeInfo *real_typeinfo;
1522 GUID parentiid;
1523 HRESULT hr;
1525 TRACE("typeinfo %p, iid %s, server %p, stub_buffer %p.\n",
1526 typeinfo, debugstr_guid(iid), server, stub_buffer);
1528 hr = get_iface_info(typeinfo, &funcs, &parentfuncs, &parentiid, &real_typeinfo);
1529 if (FAILED(hr))
1530 return hr;
1532 if (!(stub = heap_alloc_zero(sizeof(*stub))))
1534 ERR("Failed to allocate stub object.\n");
1535 ITypeInfo_Release(real_typeinfo);
1536 return E_OUTOFMEMORY;
1539 init_stub_desc(&stub->stub_desc);
1540 stub->server_info.pStubDesc = &stub->stub_desc;
1542 hr = build_format_strings(real_typeinfo, funcs, parentfuncs, &stub->stub_desc.pFormatTypes,
1543 &stub->server_info.ProcString, &stub->offset_table);
1544 ITypeInfo_Release(real_typeinfo);
1545 if (FAILED(hr))
1547 heap_free(stub);
1548 return hr;
1550 stub->server_info.FmtStringOffset = &stub->offset_table[-3];
1552 stub->iid = *iid;
1553 stub->stub_vtbl.header.piid = &stub->iid;
1554 stub->stub_vtbl.header.pServerInfo = &stub->server_info;
1555 stub->stub_vtbl.header.DispatchTableCount = funcs + parentfuncs;
1557 if (!IsEqualGUID(&parentiid, &IID_IUnknown))
1559 stub->dispatch_table = heap_alloc((funcs + parentfuncs) * sizeof(void *));
1560 for (i = 3; i < parentfuncs; i++)
1561 stub->dispatch_table[i - 3] = NdrStubForwardingFunction;
1562 for (; i < funcs + parentfuncs; i++)
1563 stub->dispatch_table[i - 3] = (PRPC_STUB_FUNCTION)NdrStubCall2;
1564 stub->stub_vtbl.header.pDispatchTable = &stub->dispatch_table[-3];
1565 stub->stub_vtbl.Vtbl = CStdStubBuffer_Delegating_Vtbl;
1567 else
1568 stub->stub_vtbl.Vtbl = CStdStubBuffer_Vtbl;
1569 stub->stub_vtbl.Vtbl.Release = typelib_stub_Release;
1571 hr = typelib_stub_init(stub, server, &parentiid, stub_buffer);
1572 if (FAILED(hr))
1574 heap_free((void *)stub->stub_desc.pFormatTypes);
1575 heap_free((void *)stub->server_info.ProcString);
1576 heap_free(stub->offset_table);
1577 heap_free(stub);
1580 return hr;