windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / rpcrt4 / ndr_typelib.c
blob352f71fa68bc6964415410d3e2c4768ed6e110a0
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"
30 #include "cpsf.h"
31 #include "initguid.h"
32 #include "ndr_types.h"
33 #include "ndr_stubless.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
38 size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack);
40 #define WRITE_CHAR(str, len, val) \
41 do { if ((str)) (str)[(len)] = (val); (len)++; } while (0)
42 #define WRITE_SHORT(str, len, val) \
43 do { if ((str)) *((short *)((str) + (len))) = (val); (len) += 2; } while (0)
44 #define WRITE_INT(str, len, val) \
45 do { if ((str)) *((int *)((str) + (len))) = (val); (len) += 4; } while (0)
47 extern const ExtendedProxyFileInfo ndr_types_ProxyFileInfo;
49 static const MIDL_STUBLESS_PROXY_INFO *get_ndr_types_proxy_info(void)
51 return ndr_types_ProxyFileInfo.pProxyVtblList[0]->header.pStublessProxyInfo;
54 static const NDR_PARAM_OIF *get_ndr_types_params( unsigned int *nb_params )
56 const MIDL_STUBLESS_PROXY_INFO *proxy = get_ndr_types_proxy_info();
57 const unsigned char *format = proxy->ProcFormatString + proxy->FormatStringOffset[3];
58 const NDR_PROC_HEADER *proc = (const NDR_PROC_HEADER *)format;
59 const NDR_PROC_PARTIAL_OIF_HEADER *header;
61 if (proc->Oi_flags & Oi_HAS_RPCFLAGS)
62 format += sizeof(NDR_PROC_HEADER_RPC);
63 else
64 format += sizeof(NDR_PROC_HEADER);
66 header = (const NDR_PROC_PARTIAL_OIF_HEADER *)format;
67 format += sizeof(*header);
68 if (header->Oi2Flags.HasExtensions)
70 const NDR_PROC_HEADER_EXTS *ext = (const NDR_PROC_HEADER_EXTS *)format;
71 format += ext->Size;
73 *nb_params = header->number_of_params;
74 return (const NDR_PARAM_OIF *)format;
77 static unsigned short get_tfs_offset( int param )
79 unsigned int nb_params;
80 const NDR_PARAM_OIF *params = get_ndr_types_params( &nb_params );
82 assert( param < nb_params );
83 return params[param].u.type_offset;
86 static const unsigned char *get_type_format_string( size_t *size )
88 unsigned int nb_params;
89 const NDR_PARAM_OIF *params = get_ndr_types_params( &nb_params );
91 *size = params[nb_params - 1].u.type_offset;
92 return get_ndr_types_proxy_info()->pStubDesc->pFormatTypes;
95 static unsigned short write_oleaut_tfs(VARTYPE vt)
97 switch (vt)
99 case VT_BSTR: return get_tfs_offset( 0 );
100 case VT_UNKNOWN: return get_tfs_offset( 1 );
101 case VT_DISPATCH: return get_tfs_offset( 2 );
102 case VT_VARIANT: return get_tfs_offset( 3 );
103 case VT_SAFEARRAY: return get_tfs_offset( 4 );
105 return 0;
108 static unsigned char get_basetype(ITypeInfo *typeinfo, TYPEDESC *desc)
110 ITypeInfo *refinfo;
111 unsigned char ret;
112 TYPEATTR *attr;
114 switch (desc->vt)
116 case VT_I1: return FC_SMALL;
117 case VT_BOOL:
118 case VT_I2: return FC_SHORT;
119 case VT_INT:
120 case VT_ERROR:
121 case VT_HRESULT:
122 case VT_I4: return FC_LONG;
123 case VT_I8:
124 case VT_UI8: return FC_HYPER;
125 case VT_UI1: return FC_USMALL;
126 case VT_UI2: return FC_USHORT;
127 case VT_UINT:
128 case VT_UI4: return FC_ULONG;
129 case VT_R4: return FC_FLOAT;
130 case VT_DATE:
131 case VT_R8: return FC_DOUBLE;
132 case VT_USERDEFINED:
133 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
134 ITypeInfo_GetTypeAttr(refinfo, &attr);
135 if (attr->typekind == TKIND_ENUM)
136 ret = FC_ENUM32;
137 else if (attr->typekind == TKIND_ALIAS)
138 ret = get_basetype(refinfo, &attr->tdescAlias);
139 else
140 ret = 0;
141 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
142 ITypeInfo_Release(refinfo);
143 return ret;
144 default: return 0;
148 static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc)
150 switch (desc->vt)
152 case VT_I1:
153 case VT_UI1:
154 return 1;
155 case VT_I2:
156 case VT_UI2:
157 case VT_BOOL:
158 return 2;
159 case VT_I4:
160 case VT_UI4:
161 case VT_R4:
162 case VT_INT:
163 case VT_UINT:
164 case VT_ERROR:
165 case VT_HRESULT:
166 return 4;
167 case VT_I8:
168 case VT_UI8:
169 case VT_R8:
170 case VT_DATE:
171 return 8;
172 case VT_BSTR:
173 case VT_SAFEARRAY:
174 case VT_PTR:
175 case VT_UNKNOWN:
176 case VT_DISPATCH:
177 return sizeof(void *);
178 case VT_VARIANT:
179 return sizeof(VARIANT);
180 case VT_CARRAY:
182 unsigned int size = type_memsize(typeinfo, &desc->lpadesc->tdescElem);
183 unsigned int i;
184 for (i = 0; i < desc->lpadesc->cDims; i++)
185 size *= desc->lpadesc->rgbounds[i].cElements;
186 return size;
188 case VT_USERDEFINED:
190 unsigned int size = 0;
191 ITypeInfo *refinfo;
192 TYPEATTR *attr;
194 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
195 ITypeInfo_GetTypeAttr(refinfo, &attr);
196 size = attr->cbSizeInstance;
197 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
198 ITypeInfo_Release(refinfo);
199 return size;
201 default:
202 FIXME("unhandled type %u\n", desc->vt);
203 return 0;
207 static BOOL type_pointer_is_iface(ITypeInfo *typeinfo, TYPEDESC *tdesc)
209 ITypeInfo *refinfo;
210 BOOL ret = FALSE;
211 TYPEATTR *attr;
213 if (tdesc->vt == VT_USERDEFINED)
215 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
216 ITypeInfo_GetTypeAttr(refinfo, &attr);
218 if (attr->typekind == TKIND_INTERFACE
219 || attr->typekind == TKIND_DISPATCH
220 || attr->typekind == TKIND_COCLASS)
221 ret = TRUE;
222 else if (attr->typekind == TKIND_ALIAS)
223 ret = type_pointer_is_iface(refinfo, &attr->tdescAlias);
225 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
226 ITypeInfo_Release(refinfo);
229 return ret;
232 static unsigned char get_array_fc(ITypeInfo *typeinfo, TYPEDESC *desc);
233 static unsigned char get_struct_fc(ITypeInfo *typeinfo, TYPEATTR *attr);
235 static unsigned char get_struct_member_fc(ITypeInfo *typeinfo, TYPEDESC *tdesc)
237 unsigned char fc;
238 ITypeInfo *refinfo;
239 TYPEATTR *attr;
241 switch (tdesc->vt)
243 case VT_BSTR:
244 case VT_SAFEARRAY:
245 return (sizeof(void *) == 4) ? FC_PSTRUCT : FC_BOGUS_STRUCT;
246 case VT_CY:
247 return FC_STRUCT;
248 case VT_VARIANT:
249 case VT_UNKNOWN:
250 case VT_DISPATCH:
251 return FC_BOGUS_STRUCT;
252 case VT_CARRAY:
253 if (get_array_fc(typeinfo, &tdesc->lpadesc->tdescElem) == FC_BOGUS_ARRAY)
254 return FC_BOGUS_STRUCT;
255 return FC_STRUCT;
256 case VT_PTR:
257 if (type_pointer_is_iface(typeinfo, tdesc))
258 fc = FC_BOGUS_STRUCT;
259 else
260 fc = (sizeof(void *) == 4) ? FC_PSTRUCT : FC_BOGUS_STRUCT;
261 break;
262 case VT_USERDEFINED:
263 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
264 ITypeInfo_GetTypeAttr(refinfo, &attr);
266 switch (attr->typekind)
268 case TKIND_ENUM:
269 fc = FC_STRUCT;
270 break;
271 case TKIND_RECORD:
272 fc = get_struct_fc(refinfo, attr);
273 break;
274 case TKIND_INTERFACE:
275 case TKIND_DISPATCH:
276 case TKIND_COCLASS:
277 fc = FC_BOGUS_STRUCT;
278 break;
279 case TKIND_ALIAS:
280 fc = get_struct_member_fc(refinfo, &attr->tdescAlias);
281 break;
282 default:
283 FIXME("Unhandled kind %#x.\n", attr->typekind);
284 fc = FC_BOGUS_STRUCT;
285 break;
288 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
289 ITypeInfo_Release(refinfo);
290 break;
291 default:
292 if (get_basetype(typeinfo, tdesc))
293 return FC_STRUCT;
294 else
296 FIXME("Unhandled type %u.\n", tdesc->vt);
297 return FC_BOGUS_STRUCT;
301 return fc;
304 static unsigned char get_struct_fc(ITypeInfo *typeinfo, TYPEATTR *attr)
306 unsigned char fc = FC_STRUCT, member_fc;
307 VARDESC *desc;
308 WORD i;
310 for (i = 0; i < attr->cVars; i++)
312 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
314 member_fc = get_struct_member_fc(typeinfo, &desc->elemdescVar.tdesc);
315 if (member_fc == FC_BOGUS_STRUCT)
316 fc = FC_BOGUS_STRUCT;
317 else if (member_fc == FC_PSTRUCT && fc != FC_BOGUS_STRUCT)
318 fc = FC_PSTRUCT;
320 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
323 return fc;
326 static unsigned char get_array_fc(ITypeInfo *typeinfo, TYPEDESC *desc)
328 switch (desc->vt)
330 case VT_CY:
331 return FC_LGFARRAY;
332 case VT_CARRAY:
333 return get_array_fc(typeinfo, &desc->lpadesc->tdescElem);
334 case VT_USERDEFINED:
336 ITypeInfo *refinfo;
337 TYPEATTR *attr;
338 unsigned char fc;
340 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
341 ITypeInfo_GetTypeAttr(refinfo, &attr);
343 if (attr->typekind == TKIND_ENUM)
344 fc = FC_LGFARRAY;
345 else if (attr->typekind == TKIND_RECORD && get_struct_fc(refinfo, attr) == FC_STRUCT)
346 fc = FC_LGFARRAY;
347 else if (attr->typekind == TKIND_ALIAS)
348 fc = get_array_fc(refinfo, &attr->tdescAlias);
349 else
350 fc = FC_BOGUS_ARRAY;
352 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
353 ITypeInfo_Release(refinfo);
355 return fc;
357 default:
358 return get_basetype(typeinfo, desc) ? FC_LGFARRAY : FC_BOGUS_ARRAY;
362 static BOOL type_is_non_iface_pointer(ITypeInfo *typeinfo, TYPEDESC *desc)
364 if (desc->vt == VT_PTR)
365 return !type_pointer_is_iface(typeinfo, desc->lptdesc);
366 else if (desc->vt == VT_USERDEFINED)
368 ITypeInfo *refinfo;
369 TYPEATTR *attr;
370 BOOL ret;
372 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
373 ITypeInfo_GetTypeAttr(refinfo, &attr);
375 if (attr->typekind == TKIND_ALIAS)
376 ret = type_is_non_iface_pointer(refinfo, &attr->tdescAlias);
377 else
378 ret = FALSE;
380 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
381 ITypeInfo_Release(refinfo);
383 return ret;
385 else
386 return FALSE;
389 static void write_struct_members(ITypeInfo *typeinfo, unsigned char *str,
390 size_t *len, TYPEATTR *attr)
392 unsigned int struct_offset = 0;
393 unsigned char basetype;
394 TYPEDESC *tdesc;
395 VARDESC *desc;
396 WORD i;
398 for (i = 0; i < attr->cVars; i++)
400 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
401 tdesc = &desc->elemdescVar.tdesc;
403 /* This may not match the intended alignment, but we don't have enough
404 * information to determine that. This should always give the correct
405 * layout. */
406 if ((struct_offset & 7) && !(desc->oInst & 7))
407 WRITE_CHAR(str, *len, FC_ALIGNM8);
408 else if ((struct_offset & 3) && !(desc->oInst & 3))
409 WRITE_CHAR(str, *len, FC_ALIGNM4);
410 else if ((struct_offset & 1) && !(desc->oInst & 1))
411 WRITE_CHAR(str, *len, FC_ALIGNM2);
412 struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
414 if ((basetype = get_basetype(typeinfo, tdesc)))
415 WRITE_CHAR(str, *len, basetype);
416 else if (type_is_non_iface_pointer(typeinfo, tdesc))
417 WRITE_CHAR(str, *len, FC_POINTER);
418 else
420 WRITE_CHAR(str, *len, FC_EMBEDDED_COMPLEX);
421 WRITE_CHAR(str, *len, 0);
422 WRITE_SHORT(str, *len, 0);
425 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
427 if (!(*len & 1))
428 WRITE_CHAR (str, *len, FC_PAD);
429 WRITE_CHAR (str, *len, FC_END);
432 static void write_simple_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
433 size_t *len, TYPEATTR *attr)
435 write_struct_members(typeinfo, str, len, attr);
438 static BOOL type_needs_pointer_deref(ITypeInfo *typeinfo, TYPEDESC *desc)
440 if (desc->vt == VT_PTR || desc->vt == VT_UNKNOWN || desc->vt == VT_DISPATCH)
441 return TRUE;
442 else if (desc->vt == VT_USERDEFINED)
444 ITypeInfo *refinfo;
445 BOOL ret = FALSE;
446 TYPEATTR *attr;
448 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
449 ITypeInfo_GetTypeAttr(refinfo, &attr);
451 if (attr->typekind == TKIND_ALIAS)
452 ret = type_needs_pointer_deref(refinfo, &attr->tdescAlias);
454 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
455 ITypeInfo_Release(refinfo);
457 return ret;
459 else
460 return FALSE;
463 static void write_complex_struct_pointer_layout(ITypeInfo *typeinfo,
464 TYPEDESC *desc, unsigned char *str, size_t *len)
466 unsigned char basetype;
468 if (desc->vt == VT_PTR && !type_pointer_is_iface(typeinfo, desc->lptdesc))
470 WRITE_CHAR(str, *len, FC_UP);
471 if ((basetype = get_basetype(typeinfo, desc->lptdesc)))
473 WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
474 WRITE_CHAR(str, *len, basetype);
475 WRITE_CHAR(str, *len, FC_PAD);
477 else
479 if (type_needs_pointer_deref(typeinfo, desc->lptdesc))
480 WRITE_CHAR(str, *len, FC_POINTER_DEREF);
481 else
482 WRITE_CHAR(str, *len, 0);
483 WRITE_SHORT(str, *len, 0);
486 else if (desc->vt == VT_USERDEFINED)
488 ITypeInfo *refinfo;
489 TYPEATTR *attr;
491 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
492 ITypeInfo_GetTypeAttr(refinfo, &attr);
494 if (attr->typekind == TKIND_ALIAS)
495 write_complex_struct_pointer_layout(refinfo, &attr->tdescAlias, str, len);
497 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
498 ITypeInfo_Release(refinfo);
502 static size_t write_complex_struct_pointer_ref(ITypeInfo *typeinfo,
503 TYPEDESC *desc, unsigned char *str, size_t *len)
505 if (desc->vt == VT_PTR && !type_pointer_is_iface(typeinfo, desc->lptdesc)
506 && !get_basetype(typeinfo, desc->lptdesc))
508 return write_type_tfs(typeinfo, str, len, desc->lptdesc, FALSE, FALSE);
510 else if (desc->vt == VT_USERDEFINED)
512 ITypeInfo *refinfo;
513 TYPEATTR *attr;
514 size_t ret = 0;
516 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
517 ITypeInfo_GetTypeAttr(refinfo, &attr);
519 if (attr->typekind == TKIND_ALIAS)
520 ret = write_complex_struct_pointer_ref(refinfo, &attr->tdescAlias, str, len);
522 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
523 ITypeInfo_Release(refinfo);
525 return ret;
528 return 0;
531 static void write_complex_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
532 size_t *len, TYPEATTR *attr)
534 size_t pointer_layout_offset, pointer_layout, member_layout, ref;
535 unsigned int struct_offset = 0;
536 TYPEDESC *tdesc;
537 VARDESC *desc;
538 WORD i;
540 WRITE_SHORT(str, *len, 0); /* conformant array description */
541 pointer_layout_offset = *len;
542 WRITE_SHORT(str, *len, 0); /* pointer layout; will be filled in later */
543 member_layout = *len;
545 /* First pass: write the struct members and pointer layout, but do not yet
546 * write the offsets for embedded complexes and pointer refs. These must be
547 * handled after we write the whole struct description, since it must be
548 * contiguous. */
550 write_struct_members(typeinfo, str, len, attr);
552 pointer_layout = *len;
553 if (str) *((short *)(str + pointer_layout_offset)) = pointer_layout - pointer_layout_offset;
555 for (i = 0; i < attr->cVars; i++)
557 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
558 write_complex_struct_pointer_layout(typeinfo, &desc->elemdescVar.tdesc, str, len);
559 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
562 /* Second pass: write types for embedded complexes and non-simple pointers. */
564 struct_offset = 0;
566 for (i = 0; i < attr->cVars; i++)
568 ITypeInfo_GetVarDesc(typeinfo, i, &desc);
569 tdesc = &desc->elemdescVar.tdesc;
571 if (struct_offset != desc->oInst)
572 member_layout++; /* alignment directive */
573 struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
575 if (get_basetype(typeinfo, tdesc))
576 member_layout++;
577 else if (type_is_non_iface_pointer(typeinfo, tdesc))
579 member_layout++;
580 if ((ref = write_complex_struct_pointer_ref(typeinfo, tdesc, str, len)))
582 if (str) *((short *)(str + pointer_layout + 2)) = ref - (pointer_layout + 2);
584 pointer_layout += 4;
586 else
588 ref = write_type_tfs(typeinfo, str, len, tdesc, FALSE, FALSE);
589 if (str) *((short *)(str + member_layout + 2)) = ref - (member_layout + 2);
590 member_layout += 4;
593 ITypeInfo_ReleaseVarDesc(typeinfo, desc);
597 static size_t write_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
598 size_t *len, TYPEATTR *attr)
600 unsigned char fc = get_struct_fc(typeinfo, attr);
601 size_t off = *len;
603 /* For the sake of simplicity, write pointer structs as complex structs. */
604 if (fc == FC_PSTRUCT)
605 fc = FC_BOGUS_STRUCT;
607 WRITE_CHAR (str, *len, fc);
608 WRITE_CHAR (str, *len, attr->cbAlignment - 1);
609 WRITE_SHORT(str, *len, attr->cbSizeInstance);
611 if (fc == FC_STRUCT)
612 write_simple_struct_tfs(typeinfo, str, len, attr);
613 else if (fc == FC_BOGUS_STRUCT)
614 write_complex_struct_tfs(typeinfo, str, len, attr);
616 return off;
619 static size_t write_array_tfs(ITypeInfo *typeinfo, unsigned char *str,
620 size_t *len, ARRAYDESC *desc)
622 unsigned char fc = get_array_fc(typeinfo, &desc->tdescElem);
623 unsigned char basetype;
624 size_t ref = 0, off;
625 ULONG size = 1;
626 USHORT i;
628 if (!(basetype = get_basetype(typeinfo, &desc->tdescElem)))
629 ref = write_type_tfs(typeinfo, str, len, &desc->tdescElem, FALSE, FALSE);
631 /* In theory arrays should be nested, but there's no reason not to marshal
632 * [x][y] as [x*y]. */
633 for (i = 0; i < desc->cDims; i++) size *= desc->rgbounds[i].cElements;
635 off = *len;
637 WRITE_CHAR(str, *len, fc);
638 WRITE_CHAR(str, *len, 0);
639 if (fc == FC_BOGUS_ARRAY)
641 WRITE_SHORT(str, *len, size);
642 WRITE_INT(str, *len, 0xffffffff); /* conformance */
643 WRITE_INT(str, *len, 0xffffffff); /* variance */
645 else
647 size *= type_memsize(typeinfo, &desc->tdescElem);
648 WRITE_INT(str, *len, size);
651 if (basetype)
652 WRITE_CHAR(str, *len, basetype);
653 else
655 WRITE_CHAR (str, *len, FC_EMBEDDED_COMPLEX);
656 WRITE_CHAR (str, *len, 0);
657 WRITE_SHORT(str, *len, ref - *len);
658 WRITE_CHAR (str, *len, FC_PAD);
660 WRITE_CHAR(str, *len, FC_END);
662 return off;
665 static size_t write_ip_tfs(unsigned char *str, size_t *len, const GUID *iid)
667 size_t off = *len;
669 if (str)
671 str[*len] = FC_IP;
672 str[*len+1] = FC_CONSTANT_IID;
673 memcpy(str + *len + 2, iid, sizeof(*iid));
675 *len += 2 + sizeof(*iid);
677 return off;
680 static void get_default_iface(ITypeInfo *typeinfo, WORD count, GUID *iid)
682 ITypeInfo *refinfo;
683 HREFTYPE reftype;
684 TYPEATTR *attr;
685 int flags, i;
687 for (i = 0; i < count; ++i)
689 ITypeInfo_GetImplTypeFlags(typeinfo, i, &flags);
690 if (flags & IMPLTYPEFLAG_FDEFAULT)
691 break;
694 /* If no interface was explicitly marked default, choose the first one. */
695 if (i == count)
696 i = 0;
698 ITypeInfo_GetRefTypeOfImplType(typeinfo, i, &reftype);
699 ITypeInfo_GetRefTypeInfo(typeinfo, reftype, &refinfo);
700 ITypeInfo_GetTypeAttr(refinfo, &attr);
701 *iid = attr->guid;
702 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
703 ITypeInfo_Release(refinfo);
706 static size_t write_pointer_tfs(ITypeInfo *typeinfo, unsigned char *str,
707 size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack)
709 unsigned char basetype, flags = 0;
710 size_t ref, off = *len;
711 ITypeInfo *refinfo;
712 TYPEATTR *attr;
713 GUID guid;
715 if (desc->vt == VT_USERDEFINED)
717 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
718 ITypeInfo_GetTypeAttr(refinfo, &attr);
720 switch (attr->typekind)
722 case TKIND_ENUM:
723 assert(!toplevel); /* toplevel base-type pointers should use IsSimpleRef */
724 WRITE_CHAR(str, *len, FC_UP);
725 WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
726 WRITE_CHAR(str, *len, FC_ENUM32);
727 WRITE_CHAR(str, *len, FC_PAD);
728 break;
729 case TKIND_RECORD:
730 assert(!toplevel); /* toplevel struct pointers should use IsSimpleRef */
731 ref = write_struct_tfs(refinfo, str, len, attr);
732 off = *len;
733 WRITE_CHAR (str, *len, FC_UP);
734 WRITE_CHAR (str, *len, 0);
735 WRITE_SHORT(str, *len, ref - *len);
736 break;
737 case TKIND_INTERFACE:
738 case TKIND_DISPATCH:
739 write_ip_tfs(str, len, &attr->guid);
740 break;
741 case TKIND_COCLASS:
742 get_default_iface(refinfo, attr->cImplTypes, &guid);
743 write_ip_tfs(str, len, &guid);
744 break;
745 case TKIND_ALIAS:
746 off = write_pointer_tfs(refinfo, str, len, &attr->tdescAlias, toplevel, onstack);
747 break;
748 default:
749 FIXME("unhandled kind %#x\n", attr->typekind);
750 WRITE_SHORT(str, *len, 0);
751 break;
754 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
755 ITypeInfo_Release(refinfo);
757 else if ((basetype = get_basetype(typeinfo, desc)))
759 assert(!toplevel); /* toplevel base-type pointers should use IsSimpleRef */
760 WRITE_CHAR(str, *len, FC_UP);
761 WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
762 WRITE_CHAR(str, *len, basetype);
763 WRITE_CHAR(str, *len, FC_PAD);
765 else
767 ref = write_type_tfs(typeinfo, str, len, desc, FALSE, FALSE);
769 if (onstack) flags |= FC_ALLOCED_ON_STACK;
770 if (desc->vt == VT_PTR || desc->vt == VT_UNKNOWN || desc->vt == VT_DISPATCH)
771 flags |= FC_POINTER_DEREF;
773 off = *len;
775 WRITE_CHAR (str, *len, toplevel ? FC_RP : FC_UP);
776 WRITE_CHAR (str, *len, flags);
777 WRITE_SHORT(str, *len, ref - *len);
780 return off;
783 static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
784 size_t *len, TYPEDESC *desc, BOOL toplevel, BOOL onstack)
786 ITypeInfo *refinfo;
787 TYPEATTR *attr;
788 size_t off;
789 GUID guid;
791 TRACE("vt %d%s\n", desc->vt, toplevel ? " (toplevel)" : "");
793 if ((off = write_oleaut_tfs(desc->vt)))
794 return off;
796 switch (desc->vt)
798 case VT_PTR:
799 return write_pointer_tfs(typeinfo, str, len, desc->lptdesc, toplevel, onstack);
800 case VT_CARRAY:
801 return write_array_tfs(typeinfo, str, len, desc->lpadesc);
802 case VT_USERDEFINED:
803 ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
804 ITypeInfo_GetTypeAttr(refinfo, &attr);
806 switch (attr->typekind)
808 case TKIND_RECORD:
809 off = write_struct_tfs(refinfo, str, len, attr);
810 break;
811 case TKIND_INTERFACE:
812 case TKIND_DISPATCH:
813 /* These are treated as if they were interface pointers. */
814 off = *len;
815 write_ip_tfs(str, len, &attr->guid);
816 break;
817 case TKIND_COCLASS:
818 off = *len;
819 get_default_iface(refinfo, attr->cImplTypes, &guid);
820 write_ip_tfs(str, len, &guid);
821 break;
822 case TKIND_ALIAS:
823 off = write_type_tfs(refinfo, str, len, &attr->tdescAlias, toplevel, onstack);
824 break;
825 default:
826 FIXME("unhandled kind %u\n", attr->typekind);
827 off = *len;
828 WRITE_SHORT(str, *len, 0);
829 break;
832 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
833 ITypeInfo_Release(refinfo);
834 break;
835 default:
836 /* base types are always embedded directly */
837 assert(!get_basetype(typeinfo, desc));
838 FIXME("unhandled type %u\n", desc->vt);
839 off = *len;
840 WRITE_SHORT(str, *len, 0);
841 break;
844 return off;
847 static unsigned short get_stack_size(ITypeInfo *typeinfo, TYPEDESC *desc)
849 #if defined(__i386__) || defined(__arm__)
850 if (desc->vt == VT_CARRAY)
851 return sizeof(void *);
852 return (type_memsize(typeinfo, desc) + 3) & ~3;
853 #else
854 return sizeof(void *);
855 #endif
858 static const unsigned short MustSize = 0x0001;
859 static const unsigned short MustFree = 0x0002;
860 static const unsigned short IsIn = 0x0008;
861 static const unsigned short IsOut = 0x0010;
862 static const unsigned short IsReturn = 0x0020;
863 static const unsigned short IsBasetype = 0x0040;
864 static const unsigned short IsByValue = 0x0080;
865 static const unsigned short IsSimpleRef = 0x0100;
867 static HRESULT get_param_pointer_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
868 int is_out, unsigned short *server_size, unsigned short *flags,
869 unsigned char *basetype, TYPEDESC **tfs_tdesc)
871 ITypeInfo *refinfo;
872 HRESULT hr = S_OK;
873 TYPEATTR *attr;
875 switch (tdesc->vt)
877 case VT_UNKNOWN:
878 case VT_DISPATCH:
879 *flags |= MustFree;
880 if (is_in && is_out)
881 *server_size = sizeof(void *);
882 break;
883 case VT_PTR:
884 *flags |= MustFree;
885 if (type_pointer_is_iface(typeinfo, tdesc->lptdesc))
887 if (is_in && is_out)
888 *server_size = sizeof(void *);
890 else
891 *server_size = sizeof(void *);
892 break;
893 case VT_CARRAY:
894 *flags |= IsSimpleRef | MustFree;
895 *server_size = type_memsize(typeinfo, tdesc);
896 *tfs_tdesc = tdesc;
897 break;
898 case VT_USERDEFINED:
899 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
900 ITypeInfo_GetTypeAttr(refinfo, &attr);
902 switch (attr->typekind)
904 case TKIND_ENUM:
905 *flags |= IsSimpleRef | IsBasetype;
906 if (!is_in && is_out)
907 *server_size = sizeof(void *);
908 *basetype = FC_ENUM32;
909 break;
910 case TKIND_RECORD:
911 *flags |= IsSimpleRef | MustFree;
912 if (!is_in && is_out)
913 *server_size = attr->cbSizeInstance;
914 *tfs_tdesc = tdesc;
915 break;
916 case TKIND_INTERFACE:
917 case TKIND_DISPATCH:
918 case TKIND_COCLASS:
919 *flags |= MustFree;
920 break;
921 case TKIND_ALIAS:
922 hr = get_param_pointer_info(refinfo, &attr->tdescAlias, is_in,
923 is_out, server_size, flags, basetype, tfs_tdesc);
924 break;
925 default:
926 FIXME("unhandled kind %#x\n", attr->typekind);
927 hr = E_NOTIMPL;
928 break;
931 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
932 ITypeInfo_Release(refinfo);
933 break;
934 default:
935 *flags |= IsSimpleRef;
936 *tfs_tdesc = tdesc;
937 if (!is_in && is_out)
938 *server_size = type_memsize(typeinfo, tdesc);
939 if ((*basetype = get_basetype(typeinfo, tdesc)))
940 *flags |= IsBasetype;
941 else
942 *flags |= MustFree;
943 break;
946 return hr;
949 static HRESULT get_param_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
950 int is_out, unsigned short *server_size, unsigned short *flags,
951 unsigned char *basetype, TYPEDESC **tfs_tdesc)
953 ITypeInfo *refinfo;
954 HRESULT hr = S_OK;
955 TYPEATTR *attr;
957 *server_size = 0;
958 *flags = MustSize;
959 *basetype = 0;
960 *tfs_tdesc = tdesc;
962 TRACE("vt %u\n", tdesc->vt);
964 switch (tdesc->vt)
966 case VT_VARIANT:
967 #if !defined(__i386__) && !defined(__arm__)
968 *flags |= IsSimpleRef | MustFree;
969 break;
970 #endif
971 /* otherwise fall through */
972 case VT_BSTR:
973 case VT_SAFEARRAY:
974 case VT_CY:
975 *flags |= IsByValue | MustFree;
976 break;
977 case VT_UNKNOWN:
978 case VT_DISPATCH:
979 case VT_CARRAY:
980 *flags |= MustFree;
981 break;
982 case VT_PTR:
983 return get_param_pointer_info(typeinfo, tdesc->lptdesc, is_in, is_out,
984 server_size, flags, basetype, tfs_tdesc);
985 case VT_USERDEFINED:
986 ITypeInfo_GetRefTypeInfo(typeinfo, tdesc->hreftype, &refinfo);
987 ITypeInfo_GetTypeAttr(refinfo, &attr);
989 switch (attr->typekind)
991 case TKIND_ENUM:
992 *flags |= IsBasetype;
993 *basetype = FC_ENUM32;
994 break;
995 case TKIND_RECORD:
996 #if defined(__i386__) || defined(__arm__)
997 *flags |= IsByValue | MustFree;
998 #else
999 if (attr->cbSizeInstance <= 8)
1000 *flags |= IsByValue | MustFree;
1001 else
1002 *flags |= IsSimpleRef | MustFree;
1003 #endif
1004 break;
1005 case TKIND_ALIAS:
1006 hr = get_param_info(refinfo, &attr->tdescAlias, is_in, is_out,
1007 server_size, flags, basetype, tfs_tdesc);
1008 break;
1010 case TKIND_INTERFACE:
1011 case TKIND_DISPATCH:
1012 case TKIND_COCLASS:
1013 /* These are treated as if they were interface pointers. */
1014 *flags |= MustFree;
1015 break;
1017 default:
1018 FIXME("unhandled kind %#x\n", attr->typekind);
1019 hr = E_NOTIMPL;
1020 break;
1023 ITypeInfo_ReleaseTypeAttr(refinfo, attr);
1024 ITypeInfo_Release(refinfo);
1025 break;
1026 default:
1027 if ((*basetype = get_basetype(typeinfo, tdesc)))
1028 *flags |= IsBasetype;
1029 else
1031 FIXME("unhandled type %u\n", tdesc->vt);
1032 return E_NOTIMPL;
1034 break;
1037 return hr;
1040 static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
1041 size_t *typelen, unsigned char *proc, size_t *proclen, ELEMDESC *desc,
1042 BOOL is_return, unsigned short *stack_offset)
1044 USHORT param_flags = desc->paramdesc.wParamFlags;
1045 TYPEDESC *tdesc = &desc->tdesc, *tfs_tdesc;
1046 unsigned short server_size;
1047 unsigned short stack_size = get_stack_size(typeinfo, tdesc);
1048 unsigned char basetype;
1049 unsigned short flags;
1050 int is_in, is_out;
1051 size_t off = 0;
1052 HRESULT hr;
1054 is_out = param_flags & PARAMFLAG_FOUT;
1055 is_in = (param_flags & PARAMFLAG_FIN) || (!is_out && !is_return);
1057 hr = get_param_info(typeinfo, tdesc, is_in, is_out, &server_size, &flags,
1058 &basetype, &tfs_tdesc);
1060 if (is_in) flags |= IsIn;
1061 if (is_out) flags |= IsOut;
1062 if (is_return) flags |= IsOut | IsReturn;
1064 server_size = (server_size + 7) / 8;
1065 if (server_size >= 8) server_size = 0;
1066 flags |= server_size << 13;
1068 if (!basetype)
1069 off = write_type_tfs(typeinfo, type, typelen, tfs_tdesc, TRUE, server_size != 0);
1071 if (SUCCEEDED(hr))
1073 WRITE_SHORT(proc, *proclen, flags);
1074 WRITE_SHORT(proc, *proclen, *stack_offset);
1075 WRITE_SHORT(proc, *proclen, basetype ? basetype : off);
1077 *stack_offset += stack_size;
1080 return hr;
1083 static void write_proc_func_header(ITypeInfo *typeinfo, FUNCDESC *desc,
1084 WORD proc_idx, unsigned char *proc, size_t *proclen)
1086 unsigned short stack_size = 2 * sizeof(void *); /* This + return */
1087 #ifdef __x86_64__
1088 unsigned short float_mask = 0;
1089 unsigned char basetype;
1090 #endif
1091 WORD param_idx;
1093 WRITE_CHAR (proc, *proclen, FC_AUTO_HANDLE);
1094 WRITE_CHAR (proc, *proclen, Oi_OBJECT_PROC | Oi_OBJ_USE_V2_INTERPRETER);
1095 WRITE_SHORT(proc, *proclen, proc_idx);
1096 for (param_idx = 0; param_idx < desc->cParams; param_idx++)
1097 stack_size += get_stack_size(typeinfo, &desc->lprgelemdescParam[param_idx].tdesc);
1098 WRITE_SHORT(proc, *proclen, stack_size);
1100 WRITE_SHORT(proc, *proclen, 0); /* constant_client_buffer_size */
1101 WRITE_SHORT(proc, *proclen, 0); /* constant_server_buffer_size */
1102 #ifdef __x86_64__
1103 WRITE_CHAR (proc, *proclen, 0x47); /* HasExtensions | HasReturn | ClientMustSize | ServerMustSize */
1104 #else
1105 WRITE_CHAR (proc, *proclen, 0x07); /* HasReturn | ClientMustSize | ServerMustSize */
1106 #endif
1107 WRITE_CHAR (proc, *proclen, desc->cParams + 1); /* incl. return value */
1108 #ifdef __x86_64__
1109 WRITE_CHAR (proc, *proclen, 10); /* extension size */
1110 WRITE_CHAR (proc, *proclen, 0); /* INTERPRETER_OPT_FLAGS2 */
1111 WRITE_SHORT(proc, *proclen, 0); /* ClientCorrHint */
1112 WRITE_SHORT(proc, *proclen, 0); /* ServerCorrHint */
1113 WRITE_SHORT(proc, *proclen, 0); /* NotifyIndex */
1114 for (param_idx = 0; param_idx < desc->cParams && param_idx < 3; param_idx++)
1116 basetype = get_basetype(typeinfo, &desc->lprgelemdescParam[param_idx].tdesc);
1117 if (basetype == FC_FLOAT)
1118 float_mask |= (1 << ((param_idx + 1) * 2));
1119 else if (basetype == FC_DOUBLE)
1120 float_mask |= (2 << ((param_idx + 1) * 2));
1122 WRITE_SHORT(proc, *proclen, float_mask);
1123 #endif
1126 static HRESULT write_iface_fs(ITypeInfo *typeinfo, WORD funcs, WORD parentfuncs,
1127 unsigned char *type, size_t *typelen, unsigned char *proc,
1128 size_t *proclen, unsigned short *offset)
1130 unsigned short stack_offset;
1131 WORD proc_idx, param_idx;
1132 FUNCDESC *desc;
1133 HRESULT hr;
1135 for (proc_idx = 3; proc_idx < parentfuncs; proc_idx++)
1137 if (offset)
1138 offset[proc_idx - 3] = -1;
1141 for (proc_idx = 0; proc_idx < funcs; proc_idx++)
1143 TRACE("Writing procedure %d.\n", proc_idx);
1145 hr = ITypeInfo_GetFuncDesc(typeinfo, proc_idx, &desc);
1146 if (FAILED(hr)) return hr;
1148 if (offset)
1149 offset[proc_idx + parentfuncs - 3] = *proclen;
1151 write_proc_func_header(typeinfo, desc, proc_idx + parentfuncs, proc, proclen);
1153 stack_offset = sizeof(void *); /* This */
1154 for (param_idx = 0; param_idx < desc->cParams; param_idx++)
1156 TRACE("Writing parameter %d.\n", param_idx);
1157 hr = write_param_fs(typeinfo, type, typelen, proc, proclen,
1158 &desc->lprgelemdescParam[param_idx], FALSE, &stack_offset);
1159 if (FAILED(hr))
1161 ITypeInfo_ReleaseFuncDesc(typeinfo, desc);
1162 return hr;
1166 hr = write_param_fs(typeinfo, type, typelen, proc, proclen,
1167 &desc->elemdescFunc, TRUE, &stack_offset);
1168 ITypeInfo_ReleaseFuncDesc(typeinfo, desc);
1169 if (FAILED(hr)) return hr;
1172 return S_OK;
1175 static HRESULT build_format_strings(ITypeInfo *typeinfo, WORD funcs,
1176 WORD parentfuncs, const unsigned char **type_ret,
1177 const unsigned char **proc_ret, unsigned short **offset_ret)
1179 size_t tfs_size;
1180 const unsigned char *tfs = get_type_format_string( &tfs_size );
1181 size_t typelen = tfs_size, proclen = 0;
1182 unsigned char *type, *proc;
1183 unsigned short *offset;
1184 HRESULT hr;
1186 hr = write_iface_fs(typeinfo, funcs, parentfuncs, NULL, &typelen, NULL, &proclen, NULL);
1187 if (FAILED(hr)) return hr;
1189 type = malloc(typelen);
1190 proc = malloc(proclen);
1191 offset = malloc((parentfuncs + funcs - 3) * sizeof(*offset));
1192 if (!type || !proc || !offset)
1194 ERR("Failed to allocate format strings.\n");
1195 hr = E_OUTOFMEMORY;
1196 goto err;
1199 memcpy(type, tfs, tfs_size);
1200 typelen = tfs_size;
1201 proclen = 0;
1203 hr = write_iface_fs(typeinfo, funcs, parentfuncs, type, &typelen, proc, &proclen, offset);
1204 if (SUCCEEDED(hr))
1206 *type_ret = type;
1207 *proc_ret = proc;
1208 *offset_ret = offset;
1209 return S_OK;
1212 err:
1213 free(type);
1214 free(proc);
1215 free(offset);
1216 return hr;
1219 /* Common helper for Create{Proxy,Stub}FromTypeInfo(). */
1220 static HRESULT get_iface_info(ITypeInfo *typeinfo, WORD *funcs, WORD *parentfuncs,
1221 GUID *parentiid, ITypeInfo **real_typeinfo)
1223 ITypeInfo *parentinfo;
1224 TYPEATTR *typeattr;
1225 ITypeLib *typelib;
1226 TLIBATTR *libattr;
1227 TYPEKIND typekind;
1228 HREFTYPE reftype;
1229 SYSKIND syskind;
1230 HRESULT hr;
1232 /* Dual interfaces report their size to be sizeof(IDispatchVtbl) and their
1233 * implemented type to be IDispatch. We need to retrieve the underlying
1234 * interface to get that information. */
1235 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
1236 if (FAILED(hr))
1237 return hr;
1238 typekind = typeattr->typekind;
1239 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
1240 if (typekind == TKIND_DISPATCH)
1242 hr = ITypeInfo_GetRefTypeOfImplType(typeinfo, -1, &reftype);
1243 if (FAILED(hr))
1244 return hr;
1246 hr = ITypeInfo_GetRefTypeInfo(typeinfo, reftype, real_typeinfo);
1247 if (FAILED(hr))
1248 return hr;
1250 else
1251 ITypeInfo_AddRef(*real_typeinfo = typeinfo);
1253 hr = ITypeInfo_GetContainingTypeLib(*real_typeinfo, &typelib, NULL);
1254 if (FAILED(hr))
1255 goto err;
1257 hr = ITypeLib_GetLibAttr(typelib, &libattr);
1258 if (FAILED(hr))
1260 ITypeLib_Release(typelib);
1261 goto err;
1263 syskind = libattr->syskind;
1264 ITypeLib_ReleaseTLibAttr(typelib, libattr);
1265 ITypeLib_Release(typelib);
1267 hr = ITypeInfo_GetTypeAttr(*real_typeinfo, &typeattr);
1268 if (FAILED(hr))
1269 goto err;
1270 *funcs = typeattr->cFuncs;
1271 *parentfuncs = typeattr->cbSizeVft / (syskind == SYS_WIN64 ? 8 : 4) - *funcs;
1272 ITypeInfo_ReleaseTypeAttr(*real_typeinfo, typeattr);
1274 hr = ITypeInfo_GetRefTypeOfImplType(*real_typeinfo, 0, &reftype);
1275 if (FAILED(hr))
1276 goto err;
1277 hr = ITypeInfo_GetRefTypeInfo(*real_typeinfo, reftype, &parentinfo);
1278 if (FAILED(hr))
1279 goto err;
1281 hr = ITypeInfo_GetTypeAttr(parentinfo, &typeattr);
1282 if (SUCCEEDED(hr))
1284 *parentiid = typeattr->guid;
1285 ITypeInfo_ReleaseTypeAttr(parentinfo, typeattr);
1287 ITypeInfo_Release(parentinfo);
1288 if (SUCCEEDED(hr))
1289 return hr;
1291 err:
1292 ITypeInfo_Release(*real_typeinfo);
1293 return hr;
1296 static void init_stub_desc(MIDL_STUB_DESC *desc)
1298 desc->pfnAllocate = NdrOleAllocate;
1299 desc->pfnFree = NdrOleFree;
1300 desc->Version = 0x50002;
1301 desc->aUserMarshalQuadruple = get_ndr_types_proxy_info()->pStubDesc->aUserMarshalQuadruple;
1302 /* type format string is initialized with proc format string and offset table */
1305 struct typelib_proxy
1307 StdProxyImpl proxy;
1308 IID iid;
1309 MIDL_STUB_DESC stub_desc;
1310 MIDL_STUBLESS_PROXY_INFO proxy_info;
1311 CInterfaceProxyVtbl *proxy_vtbl;
1312 unsigned short *offset_table;
1315 static ULONG WINAPI typelib_proxy_Release(IRpcProxyBuffer *iface)
1317 struct typelib_proxy *proxy = CONTAINING_RECORD(iface, struct typelib_proxy, proxy.IRpcProxyBuffer_iface);
1318 ULONG refcount = InterlockedDecrement(&proxy->proxy.RefCount);
1320 TRACE("(%p) decreasing refs to %ld\n", proxy, refcount);
1322 if (!refcount)
1324 if (proxy->proxy.pChannel)
1325 IRpcProxyBuffer_Disconnect(&proxy->proxy.IRpcProxyBuffer_iface);
1326 if (proxy->proxy.base_object)
1327 IUnknown_Release(proxy->proxy.base_object);
1328 if (proxy->proxy.base_proxy)
1329 IRpcProxyBuffer_Release(proxy->proxy.base_proxy);
1330 free((void *)proxy->stub_desc.pFormatTypes);
1331 free((void *)proxy->proxy_info.ProcFormatString);
1332 free(proxy->offset_table);
1333 free(proxy->proxy_vtbl);
1334 free(proxy);
1336 return refcount;
1339 static const IRpcProxyBufferVtbl typelib_proxy_vtbl =
1341 StdProxy_QueryInterface,
1342 StdProxy_AddRef,
1343 typelib_proxy_Release,
1344 StdProxy_Connect,
1345 StdProxy_Disconnect,
1348 static HRESULT typelib_proxy_init(struct typelib_proxy *proxy, IUnknown *outer,
1349 ULONG count, const GUID *parentiid, IRpcProxyBuffer **proxy_buffer, void **out)
1351 if (!fill_stubless_table((IUnknownVtbl *)proxy->proxy_vtbl->Vtbl, count))
1352 return E_OUTOFMEMORY;
1354 if (!outer) outer = (IUnknown *)&proxy->proxy;
1356 proxy->proxy.IRpcProxyBuffer_iface.lpVtbl = &typelib_proxy_vtbl;
1357 proxy->proxy.PVtbl = proxy->proxy_vtbl->Vtbl;
1358 proxy->proxy.RefCount = 1;
1359 proxy->proxy.piid = proxy->proxy_vtbl->header.piid;
1360 proxy->proxy.pUnkOuter = outer;
1362 if (!IsEqualGUID(parentiid, &IID_IUnknown))
1364 HRESULT hr = create_proxy(parentiid, NULL, &proxy->proxy.base_proxy,
1365 (void **)&proxy->proxy.base_object);
1366 if (FAILED(hr)) return hr;
1369 *proxy_buffer = &proxy->proxy.IRpcProxyBuffer_iface;
1370 *out = &proxy->proxy.PVtbl;
1371 IUnknown_AddRef((IUnknown *)*out);
1373 return S_OK;
1376 HRESULT WINAPI CreateProxyFromTypeInfo(ITypeInfo *typeinfo, IUnknown *outer,
1377 REFIID iid, IRpcProxyBuffer **proxy_buffer, void **out)
1379 struct typelib_proxy *proxy;
1380 WORD funcs, parentfuncs, i;
1381 ITypeInfo *real_typeinfo;
1382 GUID parentiid;
1383 HRESULT hr;
1385 TRACE("typeinfo %p, outer %p, iid %s, proxy_buffer %p, out %p.\n",
1386 typeinfo, outer, debugstr_guid(iid), proxy_buffer, out);
1388 hr = get_iface_info(typeinfo, &funcs, &parentfuncs, &parentiid, &real_typeinfo);
1389 if (FAILED(hr))
1390 return hr;
1392 if (!(proxy = calloc(1, sizeof(*proxy))))
1394 ERR("Failed to allocate proxy object.\n");
1395 ITypeInfo_Release(real_typeinfo);
1396 return E_OUTOFMEMORY;
1399 init_stub_desc(&proxy->stub_desc);
1400 proxy->proxy_info.pStubDesc = &proxy->stub_desc;
1402 proxy->proxy_vtbl = calloc(1, sizeof(proxy->proxy_vtbl->header) + (funcs + parentfuncs) * sizeof(void *));
1403 if (!proxy->proxy_vtbl)
1405 ERR("Failed to allocate proxy vtbl.\n");
1406 free(proxy);
1407 ITypeInfo_Release(real_typeinfo);
1408 return E_OUTOFMEMORY;
1410 proxy->proxy_vtbl->header.pStublessProxyInfo = &proxy->proxy_info;
1411 proxy->iid = *iid;
1412 proxy->proxy_vtbl->header.piid = &proxy->iid;
1413 fill_delegated_proxy_table((IUnknownVtbl *)proxy->proxy_vtbl->Vtbl, parentfuncs);
1414 for (i = 0; i < funcs; i++)
1415 proxy->proxy_vtbl->Vtbl[parentfuncs + i] = (void *)-1;
1417 hr = build_format_strings(real_typeinfo, funcs, parentfuncs, &proxy->stub_desc.pFormatTypes,
1418 &proxy->proxy_info.ProcFormatString, &proxy->offset_table);
1419 ITypeInfo_Release(real_typeinfo);
1420 if (FAILED(hr))
1422 free(proxy->proxy_vtbl);
1423 free(proxy);
1424 return hr;
1426 proxy->proxy_info.FormatStringOffset = &proxy->offset_table[-3];
1428 hr = typelib_proxy_init(proxy, outer, funcs + parentfuncs, &parentiid, proxy_buffer, out);
1429 if (FAILED(hr))
1431 free((void *)proxy->stub_desc.pFormatTypes);
1432 free((void *)proxy->proxy_info.ProcFormatString);
1433 free((void *)proxy->offset_table);
1434 free(proxy->proxy_vtbl);
1435 free(proxy);
1438 return hr;
1441 struct typelib_stub
1443 cstdstubbuffer_delegating_t stub;
1444 IID iid;
1445 MIDL_STUB_DESC stub_desc;
1446 MIDL_SERVER_INFO server_info;
1447 CInterfaceStubVtbl stub_vtbl;
1448 unsigned short *offset_table;
1449 PRPC_STUB_FUNCTION *dispatch_table;
1452 static ULONG WINAPI typelib_stub_Release(IRpcStubBuffer *iface)
1454 struct typelib_stub *stub = CONTAINING_RECORD(iface, struct typelib_stub, stub.stub_buffer);
1455 ULONG refcount = InterlockedDecrement(&stub->stub.stub_buffer.RefCount);
1457 TRACE("(%p) decreasing refs to %ld\n", stub, refcount);
1459 if (!refcount)
1461 /* test_Release shows that native doesn't call Disconnect here.
1462 We'll leave it in for the time being. */
1463 IRpcStubBuffer_Disconnect(iface);
1465 if (stub->stub.base_stub)
1467 IRpcStubBuffer_Release(stub->stub.base_stub);
1468 free(stub->dispatch_table);
1471 free((void *)stub->stub_desc.pFormatTypes);
1472 free((void *)stub->server_info.ProcString);
1473 free(stub->offset_table);
1474 free(stub);
1477 return refcount;
1480 static HRESULT typelib_stub_init(struct typelib_stub *stub, IUnknown *server,
1481 const GUID *parentiid, IRpcStubBuffer **stub_buffer)
1483 HRESULT hr;
1485 hr = IUnknown_QueryInterface(server, stub->stub_vtbl.header.piid,
1486 (void **)&stub->stub.stub_buffer.pvServerObject);
1487 if (FAILED(hr))
1489 WARN("Failed to get interface %s, hr %#lx.\n",
1490 debugstr_guid(stub->stub_vtbl.header.piid), hr);
1491 stub->stub.stub_buffer.pvServerObject = server;
1492 IUnknown_AddRef(server);
1495 if (!IsEqualGUID(parentiid, &IID_IUnknown))
1497 stub->stub.base_obj.lpVtbl = get_delegating_vtbl(stub->stub_vtbl.header.DispatchTableCount);
1498 hr = create_stub(parentiid, &stub->stub.base_obj, &stub->stub.base_stub);
1499 if (FAILED(hr))
1501 IUnknown_Release(stub->stub.stub_buffer.pvServerObject);
1502 return hr;
1506 stub->stub.stub_buffer.lpVtbl = &stub->stub_vtbl.Vtbl;
1507 stub->stub.stub_buffer.RefCount = 1;
1509 *stub_buffer = (IRpcStubBuffer *)&stub->stub.stub_buffer;
1510 return S_OK;
1513 HRESULT WINAPI CreateStubFromTypeInfo(ITypeInfo *typeinfo, REFIID iid,
1514 IUnknown *server, IRpcStubBuffer **stub_buffer)
1516 WORD funcs, parentfuncs, i;
1517 struct typelib_stub *stub;
1518 ITypeInfo *real_typeinfo;
1519 GUID parentiid;
1520 HRESULT hr;
1522 TRACE("typeinfo %p, iid %s, server %p, stub_buffer %p.\n",
1523 typeinfo, debugstr_guid(iid), server, stub_buffer);
1525 hr = get_iface_info(typeinfo, &funcs, &parentfuncs, &parentiid, &real_typeinfo);
1526 if (FAILED(hr))
1527 return hr;
1529 if (!(stub = calloc(1, sizeof(*stub))))
1531 ERR("Failed to allocate stub object.\n");
1532 ITypeInfo_Release(real_typeinfo);
1533 return E_OUTOFMEMORY;
1536 init_stub_desc(&stub->stub_desc);
1537 stub->server_info.pStubDesc = &stub->stub_desc;
1539 hr = build_format_strings(real_typeinfo, funcs, parentfuncs, &stub->stub_desc.pFormatTypes,
1540 &stub->server_info.ProcString, &stub->offset_table);
1541 ITypeInfo_Release(real_typeinfo);
1542 if (FAILED(hr))
1544 free(stub);
1545 return hr;
1547 stub->server_info.FmtStringOffset = &stub->offset_table[-3];
1549 stub->iid = *iid;
1550 stub->stub_vtbl.header.piid = &stub->iid;
1551 stub->stub_vtbl.header.pServerInfo = &stub->server_info;
1552 stub->stub_vtbl.header.DispatchTableCount = funcs + parentfuncs;
1554 if (!IsEqualGUID(&parentiid, &IID_IUnknown))
1556 stub->dispatch_table = malloc((funcs + parentfuncs) * sizeof(void *));
1557 for (i = 3; i < parentfuncs; i++)
1558 stub->dispatch_table[i - 3] = NdrStubForwardingFunction;
1559 for (; i < funcs + parentfuncs; i++)
1560 stub->dispatch_table[i - 3] = (PRPC_STUB_FUNCTION)NdrStubCall2;
1561 stub->stub_vtbl.header.pDispatchTable = &stub->dispatch_table[-3];
1562 stub->stub_vtbl.Vtbl = CStdStubBuffer_Delegating_Vtbl;
1564 else
1565 stub->stub_vtbl.Vtbl = CStdStubBuffer_Vtbl;
1566 stub->stub_vtbl.Vtbl.Release = typelib_stub_Release;
1568 hr = typelib_stub_init(stub, server, &parentiid, stub_buffer);
1569 if (FAILED(hr))
1571 free((void *)stub->stub_desc.pFormatTypes);
1572 free((void *)stub->server_info.ProcString);
1573 free(stub->offset_table);
1574 free(stub);
1577 return hr;