wined3d: Calling glDisableClientState() from loadVertexData() is redundant.
[wine] / dlls / oleaut32 / usrmarshal.c
1 /*
2  * Misc marshalling routines
3  *
4  * Copyright 2002 Ove Kaaven
5  * Copyright 2003 Mike Hearn
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winerror.h"
34
35 #include "ole2.h"
36 #include "oleauto.h"
37 #include "rpcproxy.h"
38 #include "typelib.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42
43 #define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align))
44 #define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align))
45 #define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align)
46 #define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align)
47
48 static CStdPSFactoryBuffer PSFactoryBuffer;
49
50 CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer)
51
52 extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo;
53
54 static const ProxyFileInfo *OLEAUT32_ProxyFileList[] = {
55   &oaidl_ProxyFileInfo,
56   NULL
57 };
58
59 HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
60 {
61   return NdrDllGetClassObject(rclsid, riid, ppv, OLEAUT32_ProxyFileList,
62                               &CLSID_PSDispatch, &PSFactoryBuffer);
63 }
64
65 static void dump_user_flags(ULONG *pFlags)
66 {
67     if (HIWORD(*pFlags) == NDR_LOCAL_DATA_REPRESENTATION)
68         TRACE("MAKELONG(NDR_LOCAL_REPRESENTATION, ");
69     else
70         TRACE("MAKELONG(0x%04x, ", HIWORD(*pFlags));
71     switch (LOWORD(*pFlags))
72     {
73         case MSHCTX_LOCAL: TRACE("MSHCTX_LOCAL)"); break;
74         case MSHCTX_NOSHAREDMEM: TRACE("MSHCTX_NOSHAREDMEM)"); break;
75         case MSHCTX_DIFFERENTMACHINE: TRACE("MSHCTX_DIFFERENTMACHINE)"); break;
76         case MSHCTX_INPROC: TRACE("MSHCTX_INPROC)"); break;
77         default: TRACE("%d)", LOWORD(*pFlags));
78     }
79 }
80
81 /* CLEANLOCALSTORAGE */
82
83 #define CLS_FUNCDESC  'f'
84 #define CLS_LIBATTR   'l'
85 #define CLS_TYPEATTR  't'
86 #define CLS_VARDESC   'v'
87
88 ULONG WINAPI CLEANLOCALSTORAGE_UserSize(ULONG *pFlags, ULONG Start, CLEANLOCALSTORAGE *pstg)
89 {
90     ALIGN_LENGTH(Start, 3);
91     return Start + sizeof(DWORD);
92 }
93
94 unsigned char * WINAPI CLEANLOCALSTORAGE_UserMarshal(ULONG *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstg)
95 {
96     ALIGN_POINTER(Buffer, 3);
97     *(DWORD*)Buffer = pstg->flags;
98     switch(pstg->flags)
99     {
100     case CLS_LIBATTR:
101         ITypeLib_ReleaseTLibAttr((ITypeLib*)pstg->pInterface, *(TLIBATTR**)pstg->pStorage);
102         break;
103     case CLS_TYPEATTR:
104         ITypeInfo_ReleaseTypeAttr((ITypeInfo*)pstg->pInterface, *(TYPEATTR**)pstg->pStorage); 
105         break;
106     case CLS_FUNCDESC:
107         ITypeInfo_ReleaseFuncDesc((ITypeInfo*)pstg->pInterface, *(FUNCDESC**)pstg->pStorage); 
108         break;
109     case CLS_VARDESC:
110         ITypeInfo_ReleaseVarDesc((ITypeInfo*)pstg->pInterface, *(VARDESC**)pstg->pStorage);
111         break;
112
113     default:
114         ERR("Unknown type %x\n", pstg->flags);
115     }
116
117     *(VOID**)pstg->pStorage = NULL;
118     IUnknown_Release(pstg->pInterface);
119     pstg->pInterface = NULL;
120
121     return Buffer + sizeof(DWORD);
122 }
123
124 unsigned char * WINAPI CLEANLOCALSTORAGE_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstr)
125 {
126     ALIGN_POINTER(Buffer, 3);
127     pstr->flags = *(DWORD*)Buffer;
128     return Buffer + sizeof(DWORD);
129 }
130
131 void WINAPI CLEANLOCALSTORAGE_UserFree(ULONG *pFlags, CLEANLOCALSTORAGE *pstr)
132 {
133     /* Nothing to do */
134 }
135
136 /* BSTR */
137
138 typedef struct
139 {
140     DWORD len;          /* No. of chars not including trailing '\0' */
141     DWORD byte_len;     /* len * 2 or 0xffffffff if len == 0 */
142     DWORD len2;         /* == len */
143 } bstr_wire_t;
144
145 ULONG WINAPI BSTR_UserSize(ULONG *pFlags, ULONG Start, BSTR *pstr)
146 {
147     TRACE("(%x,%d,%p) => %p\n", *pFlags, Start, pstr, *pstr);
148     if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
149     ALIGN_LENGTH(Start, 3);
150     Start += sizeof(bstr_wire_t) + ((SysStringByteLen(*pstr) + 1) & ~1);
151     TRACE("returning %d\n", Start);
152     return Start;
153 }
154
155 unsigned char * WINAPI BSTR_UserMarshal(ULONG *pFlags, unsigned char *Buffer, BSTR *pstr)
156 {
157     bstr_wire_t *header;
158     DWORD len = SysStringByteLen(*pstr);
159
160     TRACE("(%x,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
161     if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
162
163     ALIGN_POINTER(Buffer, 3);
164     header = (bstr_wire_t*)Buffer;
165     header->len = header->len2 = (len + 1) / 2;
166     if (*pstr)
167     {
168         header->byte_len = len;
169         memcpy(header + 1, *pstr, header->len * 2);
170     }
171     else
172         header->byte_len = 0xffffffff; /* special case for a null bstr */
173
174     return Buffer + sizeof(*header) + sizeof(OLECHAR) * header->len;
175 }
176
177 unsigned char * WINAPI BSTR_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, BSTR *pstr)
178 {
179     bstr_wire_t *header;
180     TRACE("(%x,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
181
182     ALIGN_POINTER(Buffer, 3);
183     header = (bstr_wire_t*)Buffer;
184     if(header->len != header->len2)
185         FIXME("len %08x != len2 %08x\n", header->len, header->len2);
186     
187     if(*pstr)
188     {
189         SysFreeString(*pstr);
190         *pstr = NULL;
191     }
192
193     if(header->byte_len != 0xffffffff)
194         *pstr = SysAllocStringByteLen((char*)(header + 1), header->byte_len);
195
196     if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
197     return Buffer + sizeof(*header) + sizeof(OLECHAR) * header->len;
198 }
199
200 void WINAPI BSTR_UserFree(ULONG *pFlags, BSTR *pstr)
201 {
202     TRACE("(%x,%p) => %p\n", *pFlags, pstr, *pstr);
203     if (*pstr)
204     {
205         SysFreeString(*pstr);
206         *pstr = NULL;
207     }
208 }
209
210 /* VARIANT */
211
212 typedef struct
213 {
214     DWORD clSize;
215     DWORD rpcReserverd;
216     USHORT vt;
217     USHORT wReserved1;
218     USHORT wReserved2;
219     USHORT wReserved3;
220     DWORD switch_is;
221 } variant_wire_t;
222
223 static unsigned int get_type_size(ULONG *pFlags, VARIANT *pvar)
224 {
225     if (V_VT(pvar) & VT_ARRAY) return 4;
226
227     switch (V_VT(pvar) & ~VT_BYREF) {
228     case VT_EMPTY:
229     case VT_NULL:
230         return 0;
231     case VT_I1:
232     case VT_UI1:
233         return sizeof(CHAR);
234     case VT_I2:
235     case VT_UI2:
236         return sizeof(SHORT);
237     case VT_I4:
238     case VT_UI4:
239         return sizeof(LONG);
240     case VT_INT:
241     case VT_UINT:
242         return sizeof(INT);
243     case VT_R4:
244         return sizeof(FLOAT);
245     case VT_R8:
246         return sizeof(DOUBLE);
247     case VT_BOOL:
248         return sizeof(VARIANT_BOOL);
249     case VT_ERROR:
250         return sizeof(SCODE);
251     case VT_DATE:
252         return sizeof(DATE);
253     case VT_CY:
254         return sizeof(CY);
255     case VT_DECIMAL:
256         return sizeof(DECIMAL);
257     case VT_BSTR:
258         return sizeof(BSTR);
259     case VT_VARIANT:
260         return sizeof(VARIANT);
261     case VT_UNKNOWN:
262     case VT_DISPATCH:
263     case VT_RECORD:
264         return 0;
265     default:
266         FIXME("unhandled VT %d\n", V_VT(pvar));
267         return 0;
268     }
269 }
270
271 static unsigned int get_type_alignment(ULONG *pFlags, VARIANT *pvar)
272 {
273     unsigned int size = get_type_size(pFlags, pvar);
274     if(V_VT(pvar) & VT_BYREF) return 3;
275     if(size == 0) return 0;
276     if(size <= 4) return size - 1;
277     return 7;
278 }
279
280 static unsigned interface_variant_size(ULONG *pFlags, REFIID riid, VARIANT *pvar)
281 {
282   ULONG size;
283   HRESULT hr;
284   /* find the buffer size of the marshalled dispatch interface */
285   hr = CoGetMarshalSizeMax(&size, riid, V_UNKNOWN(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
286   if (FAILED(hr)) {
287     if (!V_DISPATCH(pvar))
288       WARN("NULL dispatch pointer\n");
289     else
290       ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%x\n", hr);
291     return 0;
292   }
293   size += sizeof(ULONG); /* we have to store the buffersize in the stream */
294   TRACE("wire-size extra of dispatch variant is %d\n", size);
295   return size;
296 }
297
298 static ULONG wire_extra_user_size(ULONG *pFlags, ULONG Start, VARIANT *pvar)
299 {
300   if (V_ISARRAY(pvar))
301   {
302     if (V_ISBYREF(pvar))
303       return LPSAFEARRAY_UserSize(pFlags, Start, V_ARRAYREF(pvar));
304     else 
305       return LPSAFEARRAY_UserSize(pFlags, Start, &V_ARRAY(pvar));
306   }
307
308   switch (V_VT(pvar)) {
309   case VT_BSTR:
310     return BSTR_UserSize(pFlags, Start, &V_BSTR(pvar));
311   case VT_BSTR | VT_BYREF:
312     return BSTR_UserSize(pFlags, Start, V_BSTRREF(pvar));
313   case VT_VARIANT | VT_BYREF:
314     return VARIANT_UserSize(pFlags, Start, V_VARIANTREF(pvar));
315   case VT_UNKNOWN:
316     return Start + interface_variant_size(pFlags, &IID_IUnknown, pvar);
317   case VT_DISPATCH:
318     return Start + interface_variant_size(pFlags, &IID_IDispatch, pvar);
319   case VT_RECORD:
320     FIXME("wire-size record\n");
321     return Start;
322   case VT_SAFEARRAY:
323   case VT_SAFEARRAY | VT_BYREF:
324     FIXME("wire-size safearray: shouldn't be marshaling this\n");
325     return Start;
326   default:
327     return Start;
328   }
329 }
330
331 /* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer. returns Buffer on failure, new position otherwise */
332 static unsigned char* interface_variant_marshal(ULONG *pFlags, unsigned char *Buffer, REFIID riid, VARIANT *pvar)
333 {
334   IStream *working; 
335   HGLOBAL working_mem;
336   void *working_memlocked;
337   unsigned char *oldpos;
338   ULONG size;
339   HRESULT hr;
340   
341   TRACE("pFlags=%d, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
342
343   oldpos = Buffer;
344   
345   /* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers.
346    * We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer.
347    * in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object,
348    * but that would be overkill here, hence this implementation. We save the size because the unmarshal
349    * code has no way to know how long the marshalled buffer is. */
350
351   size = wire_extra_user_size(pFlags, 0, pvar);
352   
353   working_mem = GlobalAlloc(0, size);
354   if (!working_mem) return oldpos;
355
356   hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
357   if (hr != S_OK) {
358     GlobalFree(working_mem);
359     return oldpos;
360   }
361   
362   hr = CoMarshalInterface(working, riid, V_UNKNOWN(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
363   if (hr != S_OK) {
364     IStream_Release(working); /* this also releases the hglobal */
365     return oldpos;
366   }
367
368   working_memlocked = GlobalLock(working_mem);
369   memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */
370   memcpy(Buffer + sizeof(ULONG), working_memlocked, size - sizeof(ULONG));
371   GlobalUnlock(working_mem);
372
373   IStream_Release(working);
374
375   /* size includes the ULONG for the size written above */
376   TRACE("done, size=%d\n", size);
377   return Buffer + size;
378 }
379
380 /* helper: called for VT_DISPATCH / VT_UNKNOWN variants to unmarshal the buffer. returns Buffer on failure, new position otherwise */
381 static unsigned char *interface_variant_unmarshal(ULONG *pFlags, unsigned char *Buffer, REFIID riid, VARIANT *pvar)
382 {
383   IStream *working;
384   HGLOBAL working_mem;
385   void *working_memlocked;
386   unsigned char *oldpos;
387   ULONG size;
388   HRESULT hr;
389   
390   TRACE("pFlags=%d, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
391
392   oldpos = Buffer;
393   
394   /* get the buffersize */
395   memcpy(&size, Buffer, sizeof(ULONG));
396   TRACE("buffersize=%d\n", size);
397
398   working_mem = GlobalAlloc(0, size);
399   if (!working_mem) return oldpos;
400
401   hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
402   if (hr != S_OK) {
403     GlobalFree(working_mem);
404     return oldpos;
405   }
406
407   working_memlocked = GlobalLock(working_mem);
408   
409   /* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */
410   memcpy(working_memlocked, Buffer + sizeof(ULONG), size);
411   GlobalUnlock(working_mem);
412
413   hr = CoUnmarshalInterface(working, riid, (void**)&V_UNKNOWN(pvar));
414   if (hr != S_OK) {
415     IStream_Release(working);
416     return oldpos;
417   }
418
419   IStream_Release(working); /* this also frees the underlying hglobal */
420
421   /* size includes the ULONG for the size written above */
422   TRACE("done, processed=%d bytes\n", size);
423   return Buffer + size;
424 }
425
426
427 ULONG WINAPI VARIANT_UserSize(ULONG *pFlags, ULONG Start, VARIANT *pvar)
428 {
429     int align;
430     TRACE("(%x,%d,%p)\n", *pFlags, Start, pvar);
431     TRACE("vt=%04x\n", V_VT(pvar));
432
433     ALIGN_LENGTH(Start, 7);
434     Start += sizeof(variant_wire_t);
435     if(V_VT(pvar) & VT_BYREF)
436         Start += 4;
437
438     align = get_type_alignment(pFlags, pvar);
439     ALIGN_LENGTH(Start, align);
440     if(V_VT(pvar) == (VT_VARIANT | VT_BYREF))
441         Start += 4;
442     else
443         Start += get_type_size(pFlags, pvar);
444     Start = wire_extra_user_size(pFlags, Start, pvar);
445
446     TRACE("returning %d\n", Start);
447     return Start;
448 }
449
450 unsigned char * WINAPI VARIANT_UserMarshal(ULONG *pFlags, unsigned char *Buffer, VARIANT *pvar)
451 {
452     variant_wire_t *header;
453     ULONG type_size;
454     int align;
455     unsigned char *Pos;
456
457     TRACE("(%x,%p,%p)\n", *pFlags, Buffer, pvar);
458     TRACE("vt=%04x\n", V_VT(pvar));
459
460     ALIGN_POINTER(Buffer, 7);
461
462     header = (variant_wire_t *)Buffer; 
463
464     header->clSize = 0; /* fixed up at the end */
465     header->rpcReserverd = 0;
466     header->vt = pvar->n1.n2.vt;
467     header->wReserved1 = pvar->n1.n2.wReserved1;
468     header->wReserved2 = pvar->n1.n2.wReserved2;
469     header->wReserved3 = pvar->n1.n2.wReserved3;
470     header->switch_is = pvar->n1.n2.vt;
471     if(header->switch_is & VT_ARRAY)
472         header->switch_is &= ~VT_TYPEMASK;
473
474     Pos = (unsigned char*)(header + 1);
475     type_size = get_type_size(pFlags, pvar);
476     align = get_type_alignment(pFlags, pvar);
477     ALIGN_POINTER(Pos, align);
478
479     if(header->vt & VT_BYREF)
480     {
481         *(DWORD *)Pos = max(type_size, 4);
482         Pos += 4;
483         if((header->vt & VT_TYPEMASK) != VT_VARIANT)
484         {
485             memcpy(Pos, pvar->n1.n2.n3.byref, type_size);
486             Pos += type_size;
487         }
488         else
489         {
490             *(DWORD*)Pos = 'U' | 's' << 8 | 'e' << 16 | 'r' << 24;
491             Pos += 4;
492         }
493     } 
494     else
495     {
496         if((header->vt & VT_TYPEMASK) == VT_DECIMAL)
497             memcpy(Pos, pvar, type_size);
498         else
499             memcpy(Pos, &pvar->n1.n2.n3, type_size);
500         Pos += type_size;
501     }
502
503     if(header->vt & VT_ARRAY)
504     {
505         if(header->vt & VT_BYREF)
506             Pos = LPSAFEARRAY_UserMarshal(pFlags, Pos, V_ARRAYREF(pvar));
507         else
508             Pos = LPSAFEARRAY_UserMarshal(pFlags, Pos, &V_ARRAY(pvar));
509     }
510     else
511     {
512         switch (header->vt)
513         {
514         case VT_BSTR:
515             Pos = BSTR_UserMarshal(pFlags, Pos, &V_BSTR(pvar));
516             break;
517         case VT_BSTR | VT_BYREF:
518             Pos = BSTR_UserMarshal(pFlags, Pos, V_BSTRREF(pvar));
519             break;
520         case VT_VARIANT | VT_BYREF:
521             Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar));
522             break;
523         case VT_DISPATCH | VT_BYREF:
524             FIXME("handle DISPATCH by ref\n");
525             break;
526         case VT_UNKNOWN:
527             /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
528             Pos = interface_variant_marshal(pFlags, Pos, &IID_IUnknown, pvar);
529             break;
530         case VT_DISPATCH:
531             /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
532             Pos = interface_variant_marshal(pFlags, Pos, &IID_IDispatch, pvar);
533             break;
534         case VT_RECORD:
535             FIXME("handle BRECORD by val\n");
536             break;
537         case VT_RECORD | VT_BYREF:
538             FIXME("handle BRECORD by ref\n");
539             break;
540         }
541     }
542     header->clSize = ((Pos - Buffer) + 7) >> 3;
543     TRACE("marshalled size=%d\n", header->clSize);
544     return Pos;
545 }
546
547 unsigned char * WINAPI VARIANT_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, VARIANT *pvar)
548 {
549     variant_wire_t *header;
550     ULONG type_size;
551     int align;
552     unsigned char *Pos;
553
554     TRACE("(%x,%p,%p)\n", *pFlags, Buffer, pvar);
555
556     ALIGN_POINTER(Buffer, 7);
557     VariantClear(pvar);
558
559     header = (variant_wire_t *)Buffer; 
560     
561     pvar->n1.n2.vt = header->vt;
562     pvar->n1.n2.wReserved1 = header->wReserved1;
563     pvar->n1.n2.wReserved2 = header->wReserved2;
564     pvar->n1.n2.wReserved3 = header->wReserved3;
565
566     Pos = (unsigned char*)(header + 1);
567     type_size = get_type_size(pFlags, pvar);
568     align = get_type_alignment(pFlags, pvar);
569     ALIGN_POINTER(Pos, align);
570
571     if(header->vt & VT_BYREF)
572     {
573         Pos += 4;
574         pvar->n1.n2.n3.byref = CoTaskMemAlloc(type_size);
575         memcpy(pvar->n1.n2.n3.byref, Pos, type_size); 
576         if((header->vt & VT_TYPEMASK) != VT_VARIANT)
577            Pos += type_size;
578         else
579             Pos += 4;
580     }
581     else
582     {
583         if((header->vt & VT_TYPEMASK) == VT_DECIMAL)
584             memcpy(pvar, Pos, type_size);
585         else
586             memcpy(&pvar->n1.n2.n3, Pos, type_size);
587         Pos += type_size;
588     }
589
590     if(header->vt & VT_ARRAY)
591     {
592         if(header->vt & VT_BYREF)
593             Pos = LPSAFEARRAY_UserUnmarshal(pFlags, Pos, V_ARRAYREF(pvar));
594         else
595             Pos = LPSAFEARRAY_UserUnmarshal(pFlags, Pos, &V_ARRAY(pvar));
596     }
597     else
598     {
599         switch (header->vt)
600         {
601         case VT_BSTR:
602             V_BSTR(pvar) = NULL;
603             Pos = BSTR_UserUnmarshal(pFlags, Pos, &V_BSTR(pvar));
604             break;
605         case VT_BSTR | VT_BYREF:
606             *V_BSTRREF(pvar) = NULL;
607             Pos = BSTR_UserUnmarshal(pFlags, Pos, V_BSTRREF(pvar));
608             break;
609         case VT_VARIANT | VT_BYREF:
610             Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar));
611             break;
612         case VT_DISPATCH | VT_BYREF:
613             FIXME("handle DISPATCH by ref\n");
614             break;
615         case VT_UNKNOWN:
616             /* this should probably call WdtpInterfacePointer_UserUnmarshal in ole32.dll */
617             Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IUnknown, pvar);
618             break;
619         case VT_DISPATCH:
620             /* this should probably call WdtpInterfacePointer_UserUnmarshal in ole32.dll */
621             Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IDispatch, pvar);
622             break;
623         case VT_RECORD:
624             FIXME("handle BRECORD by val\n");
625             break;
626         case VT_RECORD | VT_BYREF:
627             FIXME("handle BRECORD by ref\n");
628             break;
629         }
630     }
631     return Pos;
632 }
633
634 void WINAPI VARIANT_UserFree(ULONG *pFlags, VARIANT *pvar)
635 {
636   VARTYPE vt = V_VT(pvar);
637   PVOID ref = NULL;
638
639   TRACE("(%x,%p)\n", *pFlags, pvar);
640   TRACE("vt=%04x\n", V_VT(pvar));
641
642   if (vt & VT_BYREF) ref = pvar->n1.n2.n3.byref;
643
644   VariantClear(pvar);
645   if (!ref) return;
646
647   if(vt & VT_ARRAY)
648     LPSAFEARRAY_UserFree(pFlags, V_ARRAYREF(pvar));
649   else
650   {
651     switch (vt)
652     {
653     case VT_BSTR | VT_BYREF:
654       BSTR_UserFree(pFlags, V_BSTRREF(pvar));
655       break;
656     case VT_VARIANT | VT_BYREF:
657       VARIANT_UserFree(pFlags, V_VARIANTREF(pvar));
658       break;
659     case VT_RECORD | VT_BYREF:
660       FIXME("handle BRECORD by ref\n");
661       break;
662     case VT_UNKNOWN | VT_BYREF:
663     case VT_DISPATCH | VT_BYREF:
664       IUnknown_Release(*V_UNKNOWNREF(pvar));
665       break;
666     }
667   }
668
669   CoTaskMemFree(ref);
670 }
671
672 /* LPSAFEARRAY */
673
674 /* Get the number of cells in a SafeArray */
675 static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa)
676 {
677     const SAFEARRAYBOUND* psab = psa->rgsabound;
678     USHORT cCount = psa->cDims;
679     ULONG ulNumCells = 1;
680
681     while (cCount--)
682     {
683         /* This is a valid bordercase. See testcases. -Marcus */
684         if (!psab->cElements)
685             return 0;
686         ulNumCells *= psab->cElements;
687         psab++;
688     }
689     return ulNumCells;
690 }
691
692 static inline SF_TYPE SAFEARRAY_GetUnionType(SAFEARRAY *psa)
693 {
694     VARTYPE vt;
695     HRESULT hr;
696
697     hr = SafeArrayGetVartype(psa, &vt);
698     if (FAILED(hr))
699     {
700         switch(psa->cbElements)
701         {
702         case 1: vt = VT_I1; break;
703         case 2: vt = VT_I2; break;
704         case 4: vt = VT_I4; break;
705         case 8: vt = VT_I8; break;
706         default:
707             RpcRaiseException(hr);
708         }
709     }
710
711     if (psa->fFeatures & FADF_HAVEIID)
712         return SF_HAVEIID;
713
714     switch (vt)
715     {
716     case VT_I1:
717     case VT_UI1:      return SF_I1;
718     case VT_BOOL:
719     case VT_I2:
720     case VT_UI2:      return SF_I2;
721     case VT_INT:
722     case VT_UINT:
723     case VT_I4:
724     case VT_UI4:
725     case VT_R4:       return SF_I4;
726     case VT_DATE:
727     case VT_CY:
728     case VT_R8:
729     case VT_I8:
730     case VT_UI8:      return SF_I8;
731     case VT_INT_PTR:
732     case VT_UINT_PTR: return (sizeof(UINT_PTR) == 4 ? SF_I4 : SF_I8);
733     case VT_BSTR:     return SF_BSTR;
734     case VT_DISPATCH: return SF_DISPATCH;
735     case VT_VARIANT:  return SF_VARIANT;
736     case VT_UNKNOWN:  return SF_UNKNOWN;
737     /* Note: Return a non-zero size to indicate vt is valid. The actual size
738      * of a UDT is taken from the result of IRecordInfo_GetSize().
739      */
740     case VT_RECORD:   return SF_RECORD;
741     default:          return SF_ERROR;
742     }
743 }
744
745 ULONG WINAPI LPSAFEARRAY_UserSize(ULONG *pFlags, ULONG StartingSize, LPSAFEARRAY *ppsa)
746 {
747     ULONG size = StartingSize;
748
749     TRACE("("); dump_user_flags(pFlags); TRACE(", %d, %p\n", StartingSize, *ppsa);
750
751     ALIGN_LENGTH(size, 3);
752     size += sizeof(ULONG_PTR);
753     if (*ppsa)
754     {
755         SAFEARRAY *psa = *ppsa;
756         ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
757         SF_TYPE sftype;
758         HRESULT hr;
759
760         size += sizeof(ULONG);
761         size += FIELD_OFFSET(struct _wireSAFEARRAY, uArrayStructs);
762
763         sftype = SAFEARRAY_GetUnionType(psa);
764         size += sizeof(ULONG);
765
766         size += sizeof(ULONG);
767         size += sizeof(ULONG_PTR);
768         if (sftype == SF_HAVEIID)
769             size += sizeof(IID);
770
771         size += sizeof(psa->rgsabound[0]) * psa->cDims;
772
773         size += sizeof(ULONG);
774
775         switch (sftype)
776         {
777             case SF_BSTR:
778             {
779                 BSTR* lpBstr;
780
781                 for (lpBstr = (BSTR*)psa->pvData; ulCellCount; ulCellCount--, lpBstr++)
782                     size = BSTR_UserSize(pFlags, size, lpBstr);
783
784                 break;
785             }
786             case SF_DISPATCH:
787             case SF_UNKNOWN:
788             case SF_HAVEIID:
789                 FIXME("size interfaces\n");
790                 break;
791             case SF_VARIANT:
792             {
793                 VARIANT* lpVariant;
794
795                 for (lpVariant = (VARIANT*)psa->pvData; ulCellCount; ulCellCount--, lpVariant++)
796                     size = VARIANT_UserSize(pFlags, size, lpVariant);
797
798                 break;
799             }
800             case SF_RECORD:
801             {
802                 IRecordInfo* pRecInfo = NULL;
803
804                 hr = SafeArrayGetRecordInfo(psa, &pRecInfo);
805                 if (FAILED(hr))
806                     RpcRaiseException(hr);
807
808                 if (pRecInfo)
809                 {
810                     FIXME("size record info %p\n", pRecInfo);
811
812                     IRecordInfo_Release(pRecInfo);
813                 }
814                 break;
815             }
816             case SF_I8:
817                 ALIGN_LENGTH(size, 7);
818                 /* fallthrough */
819             case SF_I1:
820             case SF_I2:
821             case SF_I4:
822                 size += ulCellCount * psa->cbElements;
823                 break;
824             default:
825                 break;
826         }
827
828     }
829
830     return size;
831 }
832
833 unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa)
834 {
835     HRESULT hr;
836
837     TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", Buffer, *ppsa);
838
839     ALIGN_POINTER(Buffer, 3);
840     *(ULONG_PTR *)Buffer = *ppsa ? TRUE : FALSE;
841     Buffer += sizeof(ULONG_PTR);
842     if (*ppsa)
843     {
844         VARTYPE vt;
845         SAFEARRAY *psa = *ppsa;
846         ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
847         wireSAFEARRAY wiresa;
848         SF_TYPE sftype;
849         GUID guid;
850
851         *(ULONG *)Buffer = psa->cDims;
852         Buffer += sizeof(ULONG);
853         wiresa = (wireSAFEARRAY)Buffer;
854         wiresa->cDims = psa->cDims;
855         wiresa->fFeatures = psa->fFeatures;
856         wiresa->cbElements = psa->cbElements;
857
858         hr = SafeArrayGetVartype(psa, &vt);
859         if (FAILED(hr)) vt = 0;
860
861         wiresa->cLocks = (USHORT)psa->cLocks | (vt << 16);
862
863         Buffer += FIELD_OFFSET(struct _wireSAFEARRAY, uArrayStructs);
864
865         sftype = SAFEARRAY_GetUnionType(psa);
866         *(ULONG *)Buffer = sftype;
867         Buffer += sizeof(ULONG);
868
869         *(ULONG *)Buffer = ulCellCount;
870         Buffer += sizeof(ULONG);
871         *(ULONG_PTR *)Buffer = (ULONG_PTR)psa->pvData;
872         Buffer += sizeof(ULONG_PTR);
873         if (sftype == SF_HAVEIID)
874         {
875             SafeArrayGetIID(psa, &guid);
876             memcpy(Buffer, &guid, sizeof(guid));
877             Buffer += sizeof(guid);
878         }
879
880         memcpy(Buffer, psa->rgsabound, sizeof(psa->rgsabound[0]) * psa->cDims);
881         Buffer += sizeof(psa->rgsabound[0]) * psa->cDims;
882
883         *(ULONG *)Buffer = ulCellCount;
884         Buffer += sizeof(ULONG);
885
886         if (psa->pvData)
887         {
888             switch (sftype)
889             {
890                 case SF_BSTR:
891                 {
892                     BSTR* lpBstr;
893
894                     for (lpBstr = (BSTR*)psa->pvData; ulCellCount; ulCellCount--, lpBstr++)
895                         Buffer = BSTR_UserMarshal(pFlags, Buffer, lpBstr);
896
897                     break;
898                 }
899                 case SF_DISPATCH:
900                 case SF_UNKNOWN:
901                 case SF_HAVEIID:
902                     FIXME("marshal interfaces\n");
903                     break;
904                 case SF_VARIANT:
905                 {
906                     VARIANT* lpVariant;
907
908                     for (lpVariant = (VARIANT*)psa->pvData; ulCellCount; ulCellCount--, lpVariant++)
909                         Buffer = VARIANT_UserMarshal(pFlags, Buffer, lpVariant);
910
911                     break;
912                 }
913                 case SF_RECORD:
914                 {
915                     IRecordInfo* pRecInfo = NULL;
916
917                     hr = SafeArrayGetRecordInfo(psa, &pRecInfo);
918                     if (FAILED(hr))
919                         RpcRaiseException(hr);
920
921                     if (pRecInfo)
922                     {
923                         FIXME("write record info %p\n", pRecInfo);
924
925                         IRecordInfo_Release(pRecInfo);
926                     }
927                     break;
928                 }
929
930                 case SF_I8:
931                     ALIGN_POINTER(Buffer, 7);
932                     /* fallthrough */
933                 case SF_I1:
934                 case SF_I2:
935                 case SF_I4:
936                     /* Just copy the data over */
937                     memcpy(Buffer, psa->pvData, ulCellCount * psa->cbElements);
938                     Buffer += ulCellCount * psa->cbElements;
939                     break;
940                 default:
941                     break;
942             }
943         }
944
945     }
946     return Buffer;
947 }
948
949 #define FADF_AUTOSETFLAGS (FADF_HAVEIID | FADF_RECORD | FADF_HAVEVARTYPE | \
950                            FADF_BSTR | FADF_UNKNOWN | FADF_DISPATCH | \
951                            FADF_VARIANT | FADF_CREATEVECTOR)
952
953 unsigned char * WINAPI LPSAFEARRAY_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa)
954 {
955     ULONG_PTR ptr;
956     wireSAFEARRAY wiresa;
957     ULONG cDims;
958     HRESULT hr;
959     SF_TYPE sftype;
960     ULONG cell_count;
961     GUID guid;
962     VARTYPE vt;
963     SAFEARRAYBOUND *wiresab;
964
965     TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", Buffer, ppsa);
966
967     ALIGN_POINTER(Buffer, 3);
968     ptr = *(ULONG_PTR *)Buffer;
969     Buffer += sizeof(ULONG_PTR);
970
971     if (!ptr)
972     {
973         *ppsa = NULL;
974
975         TRACE("NULL safe array unmarshaled\n");
976
977         return Buffer;
978     }
979
980     cDims = *(ULONG *)Buffer;
981     Buffer += sizeof(ULONG);
982
983     wiresa = (wireSAFEARRAY)Buffer;
984     Buffer += FIELD_OFFSET(struct _wireSAFEARRAY, uArrayStructs);
985
986     if (cDims != wiresa->cDims)
987         RpcRaiseException(RPC_S_INVALID_BOUND);
988
989     /* FIXME: there should be a limit on how large cDims can be */
990
991     vt = HIWORD(wiresa->cLocks);
992
993     sftype = *(ULONG *)Buffer;
994     Buffer += sizeof(ULONG);
995
996     cell_count = *(ULONG *)Buffer;
997     Buffer += sizeof(ULONG);
998     ptr = *(ULONG_PTR *)Buffer;
999     Buffer += sizeof(ULONG_PTR);
1000     if (sftype == SF_HAVEIID)
1001     {
1002         memcpy(&guid, Buffer, sizeof(guid));
1003         Buffer += sizeof(guid);
1004     }
1005
1006     wiresab = (SAFEARRAYBOUND *)Buffer;
1007     Buffer += sizeof(wiresab[0]) * wiresa->cDims;
1008
1009     if(vt)
1010         *ppsa = SafeArrayCreateEx(vt, wiresa->cDims, wiresab, NULL);
1011     else
1012     {
1013         SafeArrayAllocDescriptor(wiresa->cDims, ppsa);
1014         if(*ppsa)
1015             memcpy((*ppsa)->rgsabound, wiresab, sizeof(SAFEARRAYBOUND) * wiresa->cDims);
1016     }
1017     if (!*ppsa)
1018         RpcRaiseException(E_OUTOFMEMORY);
1019
1020     /* be careful about which flags we set since they could be a security
1021      * risk */
1022     (*ppsa)->fFeatures &= FADF_AUTOSETFLAGS;
1023     (*ppsa)->fFeatures |= (wiresa->fFeatures & ~(FADF_AUTOSETFLAGS));
1024     /* FIXME: there should be a limit on how large wiresa->cbElements can be */
1025     (*ppsa)->cbElements = wiresa->cbElements;
1026     (*ppsa)->cLocks = LOWORD(wiresa->cLocks);
1027
1028     hr = SafeArrayAllocData(*ppsa);
1029     if (FAILED(hr))
1030         RpcRaiseException(hr);
1031
1032     if ((*(ULONG *)Buffer != cell_count) || (SAFEARRAY_GetCellCount(*ppsa) != cell_count))
1033         RpcRaiseException(RPC_S_INVALID_BOUND);
1034     Buffer += sizeof(ULONG);
1035
1036     if (ptr)
1037     {
1038         switch (sftype)
1039         {
1040             case SF_BSTR:
1041             {
1042                 BSTR* lpBstr;
1043
1044                 for (lpBstr = (BSTR*)(*ppsa)->pvData; cell_count; cell_count--, lpBstr++)
1045                     Buffer = BSTR_UserUnmarshal(pFlags, Buffer, lpBstr);
1046
1047                 break;
1048             }
1049             case SF_DISPATCH:
1050             case SF_UNKNOWN:
1051             case SF_HAVEIID:
1052                 FIXME("marshal interfaces\n");
1053                 break;
1054             case SF_VARIANT:
1055             {
1056                 VARIANT* lpVariant;
1057
1058                 for (lpVariant = (VARIANT*)(*ppsa)->pvData; cell_count; cell_count--, lpVariant++)
1059                     Buffer = VARIANT_UserUnmarshal(pFlags, Buffer, lpVariant);
1060
1061                 break;
1062             }
1063             case SF_RECORD:
1064             {
1065                 FIXME("set record info\n");
1066
1067                 break;
1068             }
1069
1070             case SF_I8:
1071                 ALIGN_POINTER(Buffer, 7);
1072                 /* fallthrough */
1073             case SF_I1:
1074             case SF_I2:
1075             case SF_I4:
1076                 /* Just copy the data over */
1077                 memcpy((*ppsa)->pvData, Buffer, cell_count * (*ppsa)->cbElements);
1078                 Buffer += cell_count * (*ppsa)->cbElements;
1079                 break;
1080             default:
1081                 break;
1082         }
1083     }
1084
1085     TRACE("safe array unmarshaled: %p\n", *ppsa);
1086
1087     return Buffer;
1088 }
1089
1090 void WINAPI LPSAFEARRAY_UserFree(ULONG *pFlags, LPSAFEARRAY *ppsa)
1091 {
1092     TRACE("("); dump_user_flags(pFlags); TRACE(", &%p\n", *ppsa);
1093
1094     SafeArrayDestroy(*ppsa);
1095 }
1096
1097 /* IDispatch */
1098 /* exactly how Invoke is marshalled is not very clear to me yet,
1099  * but the way I've done it seems to work for me */
1100
1101 HRESULT CALLBACK IDispatch_Invoke_Proxy(
1102     IDispatch* This,
1103     DISPID dispIdMember,
1104     REFIID riid,
1105     LCID lcid,
1106     WORD wFlags,
1107     DISPPARAMS* pDispParams,
1108     VARIANT* pVarResult,
1109     EXCEPINFO* pExcepInfo,
1110     UINT* puArgErr)
1111 {
1112   HRESULT hr;
1113   VARIANT VarResult;
1114   UINT* rgVarRefIdx = NULL;
1115   VARIANTARG* rgVarRef = NULL;
1116   UINT u, cVarRef;
1117   UINT uArgErr;
1118   EXCEPINFO ExcepInfo;
1119
1120   TRACE("(%p)->(%d,%s,%x,%x,%p,%p,%p,%p)\n", This,
1121         dispIdMember, debugstr_guid(riid),
1122         lcid, wFlags, pDispParams, pVarResult,
1123         pExcepInfo, puArgErr);
1124
1125   /* [out] args can't be null, use dummy vars if needed */
1126   if (!pVarResult) pVarResult = &VarResult;
1127   if (!puArgErr) puArgErr = &uArgErr;
1128   if (!pExcepInfo) pExcepInfo = &ExcepInfo;
1129
1130   /* count by-ref args */
1131   for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) {
1132     VARIANTARG* arg = &pDispParams->rgvarg[u];
1133     if (V_ISBYREF(arg)) {
1134       cVarRef++;
1135     }
1136   }
1137   if (cVarRef) {
1138     rgVarRefIdx = CoTaskMemAlloc(sizeof(UINT)*cVarRef);
1139     rgVarRef = CoTaskMemAlloc(sizeof(VARIANTARG)*cVarRef);
1140     /* make list of by-ref args */
1141     for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) {
1142       VARIANTARG* arg = &pDispParams->rgvarg[u];
1143       if (V_ISBYREF(arg)) {
1144         rgVarRefIdx[cVarRef] = u;
1145         VariantInit(&rgVarRef[cVarRef]);
1146         cVarRef++;
1147       }
1148     }
1149   } else {
1150     /* [out] args still can't be null,
1151      * but we can point these anywhere in this case,
1152      * since they won't be written to when cVarRef is 0 */
1153     rgVarRefIdx = puArgErr;
1154     rgVarRef = pVarResult;
1155   }
1156   TRACE("passed by ref: %d args\n", cVarRef);
1157   hr = IDispatch_RemoteInvoke_Proxy(This,
1158                                     dispIdMember,
1159                                     riid,
1160                                     lcid,
1161                                     wFlags,
1162                                     pDispParams,
1163                                     pVarResult,
1164                                     pExcepInfo,
1165                                     puArgErr,
1166                                     cVarRef,
1167                                     rgVarRefIdx,
1168                                     rgVarRef);
1169   if (cVarRef) {
1170     for (u=0; u<cVarRef; u++) {
1171       unsigned i = rgVarRefIdx[u];
1172       VariantCopy(&pDispParams->rgvarg[i],
1173                   &rgVarRef[u]);
1174       VariantClear(&rgVarRef[u]);
1175     }
1176     CoTaskMemFree(rgVarRef);
1177     CoTaskMemFree(rgVarRefIdx);
1178   }
1179
1180   if(pExcepInfo == &ExcepInfo)
1181   {
1182     SysFreeString(pExcepInfo->bstrSource);
1183     SysFreeString(pExcepInfo->bstrDescription);
1184     SysFreeString(pExcepInfo->bstrHelpFile);
1185   }
1186   return hr;
1187 }
1188
1189 HRESULT __RPC_STUB IDispatch_Invoke_Stub(
1190     IDispatch* This,
1191     DISPID dispIdMember,
1192     REFIID riid,
1193     LCID lcid,
1194     DWORD dwFlags,
1195     DISPPARAMS* pDispParams,
1196     VARIANT* pVarResult,
1197     EXCEPINFO* pExcepInfo,
1198     UINT* pArgErr,
1199     UINT cVarRef,
1200     UINT* rgVarRefIdx,
1201     VARIANTARG* rgVarRef)
1202 {
1203   HRESULT hr = S_OK;
1204   VARIANTARG *rgvarg, *arg;
1205   UINT u;
1206
1207   /* initialize out parameters, so that they can be marshalled
1208    * in case the real Invoke doesn't initialize them */
1209   VariantInit(pVarResult);
1210   memset(pExcepInfo, 0, sizeof(*pExcepInfo));
1211   *pArgErr = 0;
1212
1213   /* let the real Invoke operate on a copy of the in parameters,
1214    * so we don't risk losing pointers to allocated memory */
1215   rgvarg = pDispParams->rgvarg;
1216   arg = CoTaskMemAlloc(sizeof(VARIANTARG)*pDispParams->cArgs);
1217   if (!arg) return E_OUTOFMEMORY;
1218
1219   /* init all args so we can call VariantClear on all the args if the copy
1220    * below fails */
1221   for (u = 0; u < pDispParams->cArgs; u++)
1222     VariantInit(&arg[u]);
1223
1224   for (u = 0; u < pDispParams->cArgs; u++) {
1225     hr = VariantCopy(&arg[u], &rgvarg[u]);
1226     if (FAILED(hr))
1227         break;
1228   }
1229
1230   if (SUCCEEDED(hr)) {
1231     pDispParams->rgvarg = arg;
1232
1233     hr = IDispatch_Invoke(This,
1234                           dispIdMember,
1235                           riid,
1236                           lcid,
1237                           dwFlags,
1238                           pDispParams,
1239                           pVarResult,
1240                           pExcepInfo,
1241                           pArgErr);
1242
1243     /* copy ref args to out list */
1244     for (u=0; u<cVarRef; u++) {
1245       unsigned i = rgVarRefIdx[u];
1246       VariantInit(&rgVarRef[u]);
1247       VariantCopy(&rgVarRef[u], &arg[i]);
1248       /* clear original if equal, to avoid double-free */
1249       if (V_BYREF(&rgVarRef[u]) == V_BYREF(&rgvarg[i]))
1250         VariantClear(&rgvarg[i]);
1251     }
1252   }
1253
1254   /* clear the duplicate argument list */
1255   for (u=0; u<pDispParams->cArgs; u++)
1256     VariantClear(&arg[u]);
1257
1258   pDispParams->rgvarg = rgvarg;
1259   CoTaskMemFree(arg);
1260
1261   return hr;
1262 }
1263
1264 /* IEnumVARIANT */
1265
1266 HRESULT CALLBACK IEnumVARIANT_Next_Proxy(
1267     IEnumVARIANT* This,
1268     ULONG celt,
1269     VARIANT* rgVar,
1270     ULONG* pCeltFetched)
1271 {
1272   ULONG fetched;
1273   if (!pCeltFetched)
1274     pCeltFetched = &fetched;
1275   return IEnumVARIANT_RemoteNext_Proxy(This,
1276                                        celt,
1277                                        rgVar,
1278                                        pCeltFetched);
1279 }
1280
1281 HRESULT __RPC_STUB IEnumVARIANT_Next_Stub(
1282     IEnumVARIANT* This,
1283     ULONG celt,
1284     VARIANT* rgVar,
1285     ULONG* pCeltFetched)
1286 {
1287   HRESULT hr;
1288   *pCeltFetched = 0;
1289   hr = IEnumVARIANT_Next(This,
1290                          celt,
1291                          rgVar,
1292                          pCeltFetched);
1293   if (hr == S_OK) *pCeltFetched = celt;
1294   return hr;
1295 }
1296
1297 /* TypeInfo related freers */
1298
1299 static void free_embedded_typedesc(TYPEDESC *tdesc);
1300 static void free_embedded_arraydesc(ARRAYDESC *adesc)
1301 {
1302     switch(adesc->tdescElem.vt)
1303     {
1304     case VT_PTR:
1305     case VT_SAFEARRAY:
1306         free_embedded_typedesc(adesc->tdescElem.u.lptdesc);
1307         CoTaskMemFree(adesc->tdescElem.u.lptdesc);
1308         break;
1309     case VT_CARRAY:
1310         free_embedded_arraydesc(adesc->tdescElem.u.lpadesc);
1311         CoTaskMemFree(adesc->tdescElem.u.lpadesc);
1312         break;
1313     }
1314 }
1315
1316 static void free_embedded_typedesc(TYPEDESC *tdesc)
1317 {
1318     switch(tdesc->vt)
1319     {
1320     case VT_PTR:
1321     case VT_SAFEARRAY:
1322         free_embedded_typedesc(tdesc->u.lptdesc);
1323         CoTaskMemFree(tdesc->u.lptdesc);
1324         break;
1325     case VT_CARRAY:
1326         free_embedded_arraydesc(tdesc->u.lpadesc);
1327         CoTaskMemFree(tdesc->u.lpadesc);
1328         break;
1329     }
1330 }
1331
1332 static void free_embedded_elemdesc(ELEMDESC *edesc)
1333 {
1334     free_embedded_typedesc(&edesc->tdesc);
1335     if(edesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT)
1336         CoTaskMemFree(edesc->u.paramdesc.pparamdescex);
1337 }
1338
1339 /* ITypeComp */
1340
1341 HRESULT CALLBACK ITypeComp_Bind_Proxy(
1342     ITypeComp* This,
1343     LPOLESTR szName,
1344     ULONG lHashVal,
1345     WORD wFlags,
1346     ITypeInfo** ppTInfo,
1347     DESCKIND* pDescKind,
1348     BINDPTR* pBindPtr)
1349 {
1350   FIXME("not implemented\n");
1351   return E_FAIL;
1352 }
1353
1354 HRESULT __RPC_STUB ITypeComp_Bind_Stub(
1355     ITypeComp* This,
1356     LPOLESTR szName,
1357     ULONG lHashVal,
1358     WORD wFlags,
1359     ITypeInfo** ppTInfo,
1360     DESCKIND* pDescKind,
1361     LPFUNCDESC* ppFuncDesc,
1362     LPVARDESC* ppVarDesc,
1363     ITypeComp** ppTypeComp,
1364     CLEANLOCALSTORAGE* pDummy)
1365 {
1366   FIXME("not implemented\n");
1367   return E_FAIL;
1368 }
1369
1370 HRESULT CALLBACK ITypeComp_BindType_Proxy(
1371     ITypeComp* This,
1372     LPOLESTR szName,
1373     ULONG lHashVal,
1374     ITypeInfo** ppTInfo,
1375     ITypeComp** ppTComp)
1376 {
1377   FIXME("not implemented\n");
1378   return E_FAIL;
1379 }
1380
1381 HRESULT __RPC_STUB ITypeComp_BindType_Stub(
1382     ITypeComp* This,
1383     LPOLESTR szName,
1384     ULONG lHashVal,
1385     ITypeInfo** ppTInfo)
1386 {
1387   FIXME("not implemented\n");
1388   return E_FAIL;
1389 }
1390
1391 /* ITypeInfo */
1392
1393 HRESULT CALLBACK ITypeInfo_GetTypeAttr_Proxy(
1394     ITypeInfo* This,
1395     TYPEATTR** ppTypeAttr)
1396
1397 {
1398     CLEANLOCALSTORAGE stg;
1399     TRACE("(%p, %p)\n", This, ppTypeAttr);
1400
1401     stg.flags = 0;
1402     stg.pStorage = NULL;
1403     stg.pInterface = NULL;
1404
1405     return ITypeInfo_RemoteGetTypeAttr_Proxy(This, ppTypeAttr, &stg);
1406 }
1407
1408 HRESULT __RPC_STUB ITypeInfo_GetTypeAttr_Stub(
1409     ITypeInfo* This,
1410     LPTYPEATTR* ppTypeAttr,
1411     CLEANLOCALSTORAGE* pDummy)
1412 {
1413     HRESULT hr;
1414     TRACE("(%p, %p)\n", This, ppTypeAttr);
1415
1416     hr = ITypeInfo_GetTypeAttr(This, ppTypeAttr);
1417     if(hr != S_OK)
1418         return hr;
1419
1420     pDummy->flags = CLS_TYPEATTR;
1421     ITypeInfo_AddRef(This);
1422     pDummy->pInterface = (IUnknown*)This;
1423     pDummy->pStorage = ppTypeAttr;
1424     return hr;
1425 }
1426
1427 HRESULT CALLBACK ITypeInfo_GetFuncDesc_Proxy(
1428     ITypeInfo* This,
1429     UINT index,
1430     FUNCDESC** ppFuncDesc)
1431 {
1432     CLEANLOCALSTORAGE stg;
1433     TRACE("(%p, %d, %p)\n", This, index, ppFuncDesc);
1434
1435     stg.flags = 0;
1436     stg.pStorage = NULL;
1437     stg.pInterface = NULL;
1438
1439     return ITypeInfo_RemoteGetFuncDesc_Proxy(This, index, ppFuncDesc, &stg);
1440 }
1441
1442 HRESULT __RPC_STUB ITypeInfo_GetFuncDesc_Stub(
1443     ITypeInfo* This,
1444     UINT index,
1445     LPFUNCDESC* ppFuncDesc,
1446     CLEANLOCALSTORAGE* pDummy)
1447 {
1448     HRESULT hr;
1449     TRACE("(%p, %d, %p)\n", This, index, ppFuncDesc);
1450
1451     hr = ITypeInfo_GetFuncDesc(This, index, ppFuncDesc);
1452     if(hr != S_OK)
1453         return hr;
1454
1455     pDummy->flags = CLS_FUNCDESC;
1456     ITypeInfo_AddRef(This);
1457     pDummy->pInterface = (IUnknown*)This;
1458     pDummy->pStorage = ppFuncDesc;
1459     return hr;
1460 }
1461
1462 HRESULT CALLBACK ITypeInfo_GetVarDesc_Proxy(
1463     ITypeInfo* This,
1464     UINT index,
1465     VARDESC** ppVarDesc)
1466 {
1467     CLEANLOCALSTORAGE stg;
1468     TRACE("(%p, %d, %p)\n", This, index, ppVarDesc);
1469
1470     stg.flags = 0;
1471     stg.pStorage = NULL;
1472     stg.pInterface = NULL;
1473
1474     return ITypeInfo_RemoteGetVarDesc_Proxy(This, index, ppVarDesc, &stg);
1475 }
1476
1477 HRESULT __RPC_STUB ITypeInfo_GetVarDesc_Stub(
1478     ITypeInfo* This,
1479     UINT index,
1480     LPVARDESC* ppVarDesc,
1481     CLEANLOCALSTORAGE* pDummy)
1482 {
1483     HRESULT hr;
1484     TRACE("(%p, %d, %p)\n", This, index, ppVarDesc);
1485
1486     hr = ITypeInfo_GetVarDesc(This, index, ppVarDesc);
1487     if(hr != S_OK)
1488         return hr;
1489
1490     pDummy->flags = CLS_VARDESC;
1491     ITypeInfo_AddRef(This);
1492     pDummy->pInterface = (IUnknown*)This;
1493     pDummy->pStorage = ppVarDesc;
1494     return hr;
1495 }
1496
1497 HRESULT CALLBACK ITypeInfo_GetNames_Proxy(
1498     ITypeInfo* This,
1499     MEMBERID memid,
1500     BSTR* rgBstrNames,
1501     UINT cMaxNames,
1502     UINT* pcNames)
1503 {
1504   FIXME("not implemented\n");
1505   return E_FAIL;
1506 }
1507
1508 HRESULT __RPC_STUB ITypeInfo_GetNames_Stub(
1509     ITypeInfo* This,
1510     MEMBERID memid,
1511     BSTR* rgBstrNames,
1512     UINT cMaxNames,
1513     UINT* pcNames)
1514 {
1515   FIXME("not implemented\n");
1516   return E_FAIL;
1517 }
1518
1519 HRESULT CALLBACK ITypeInfo_GetIDsOfNames_Proxy(
1520     ITypeInfo* This,
1521     LPOLESTR* rgszNames,
1522     UINT cNames,
1523     MEMBERID* pMemId)
1524 {
1525   FIXME("not implemented\n");
1526   return E_FAIL;
1527 }
1528
1529 HRESULT __RPC_STUB ITypeInfo_GetIDsOfNames_Stub(
1530     ITypeInfo* This)
1531 {
1532   FIXME("not implemented\n");
1533   return E_FAIL;
1534 }
1535
1536 HRESULT CALLBACK ITypeInfo_Invoke_Proxy(
1537     ITypeInfo* This,
1538     PVOID pvInstance,
1539     MEMBERID memid,
1540     WORD wFlags,
1541     DISPPARAMS* pDispParams,
1542     VARIANT* pVarResult,
1543     EXCEPINFO* pExcepInfo,
1544     UINT* puArgErr)
1545 {
1546   FIXME("not implemented\n");
1547   return E_FAIL;
1548 }
1549
1550 HRESULT __RPC_STUB ITypeInfo_Invoke_Stub(
1551     ITypeInfo* This)
1552 {
1553   FIXME("not implemented\n");
1554   return E_FAIL;
1555 }
1556
1557 HRESULT CALLBACK ITypeInfo_GetDocumentation_Proxy(
1558     ITypeInfo* This,
1559     MEMBERID memid,
1560     BSTR* pBstrName,
1561     BSTR* pBstrDocString,
1562     DWORD* pdwHelpContext,
1563     BSTR* pBstrHelpFile)
1564 {
1565     DWORD help_context;
1566     BSTR name, doc_string, help_file;
1567     HRESULT hr;
1568     TRACE("(%p, %08x, %p, %p, %p, %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
1569
1570     /* FIXME: presumably refPtrFlags is supposed to be a bitmask of which ptrs we actually want? */
1571     hr = ITypeInfo_RemoteGetDocumentation_Proxy(This, memid, 0, &name, &doc_string, &help_context, &help_file);
1572     if(SUCCEEDED(hr))
1573     {
1574         if(pBstrName) *pBstrName = name;
1575         else SysFreeString(name);
1576
1577         if(pBstrDocString) *pBstrDocString = doc_string;
1578         else SysFreeString(doc_string);
1579
1580         if(pBstrHelpFile) *pBstrHelpFile = help_file;
1581         else SysFreeString(help_file);
1582
1583         if(pdwHelpContext) *pdwHelpContext = help_context;
1584     }
1585     return hr;
1586 }
1587
1588 HRESULT __RPC_STUB ITypeInfo_GetDocumentation_Stub(
1589     ITypeInfo* This,
1590     MEMBERID memid,
1591     DWORD refPtrFlags,
1592     BSTR* pBstrName,
1593     BSTR* pBstrDocString,
1594     DWORD* pdwHelpContext,
1595     BSTR* pBstrHelpFile)
1596 {
1597     TRACE("(%p, %08x, %08x, %p, %p, %p, %p)\n", This, memid, refPtrFlags, pBstrName, pBstrDocString,
1598           pdwHelpContext, pBstrHelpFile);
1599     return ITypeInfo_GetDocumentation(This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
1600 }
1601
1602 HRESULT CALLBACK ITypeInfo_GetDllEntry_Proxy(
1603     ITypeInfo* This,
1604     MEMBERID memid,
1605     INVOKEKIND invKind,
1606     BSTR* pBstrDllName,
1607     BSTR* pBstrName,
1608     WORD* pwOrdinal)
1609 {
1610   FIXME("not implemented\n");
1611   return E_FAIL;
1612 }
1613
1614 HRESULT __RPC_STUB ITypeInfo_GetDllEntry_Stub(
1615     ITypeInfo* This,
1616     MEMBERID memid,
1617     INVOKEKIND invKind,
1618     DWORD refPtrFlags,
1619     BSTR* pBstrDllName,
1620     BSTR* pBstrName,
1621     WORD* pwOrdinal)
1622 {
1623   FIXME("not implemented\n");
1624   return E_FAIL;
1625 }
1626
1627 HRESULT CALLBACK ITypeInfo_AddressOfMember_Proxy(
1628     ITypeInfo* This,
1629     MEMBERID memid,
1630     INVOKEKIND invKind,
1631     PVOID* ppv)
1632 {
1633   FIXME("not implemented\n");
1634   return E_FAIL;
1635 }
1636
1637 HRESULT __RPC_STUB ITypeInfo_AddressOfMember_Stub(
1638     ITypeInfo* This)
1639 {
1640   FIXME("not implemented\n");
1641   return E_FAIL;
1642 }
1643
1644 HRESULT CALLBACK ITypeInfo_CreateInstance_Proxy(
1645     ITypeInfo* This,
1646     IUnknown* pUnkOuter,
1647     REFIID riid,
1648     PVOID* ppvObj)
1649 {
1650   FIXME("not implemented\n");
1651   return E_FAIL;
1652 }
1653
1654 HRESULT __RPC_STUB ITypeInfo_CreateInstance_Stub(
1655     ITypeInfo* This,
1656     REFIID riid,
1657     IUnknown** ppvObj)
1658 {
1659   FIXME("not implemented\n");
1660   return E_FAIL;
1661 }
1662
1663 HRESULT CALLBACK ITypeInfo_GetContainingTypeLib_Proxy(
1664     ITypeInfo* This,
1665     ITypeLib** ppTLib,
1666     UINT* pIndex)
1667 {
1668     ITypeLib *pTL;
1669     UINT index;
1670     HRESULT hr;
1671
1672     TRACE("(%p, %p, %p)\n", This, ppTLib, pIndex );
1673     
1674     hr = ITypeInfo_RemoteGetContainingTypeLib_Proxy(This, &pTL, &index);
1675     if(SUCCEEDED(hr))
1676     {
1677         if(pIndex)
1678             *pIndex = index;
1679
1680         if(ppTLib)
1681             *ppTLib = pTL;
1682         else
1683             ITypeLib_Release(pTL);
1684     }
1685     return hr;
1686 }
1687
1688 HRESULT __RPC_STUB ITypeInfo_GetContainingTypeLib_Stub(
1689     ITypeInfo* This,
1690     ITypeLib** ppTLib,
1691     UINT* pIndex)
1692 {
1693     TRACE("(%p, %p, %p)\n", This, ppTLib, pIndex );
1694     return ITypeInfo_GetContainingTypeLib(This, ppTLib, pIndex);
1695 }
1696
1697 void CALLBACK ITypeInfo_ReleaseTypeAttr_Proxy(
1698     ITypeInfo* This,
1699     TYPEATTR* pTypeAttr)
1700 {
1701     TRACE("(%p, %p)\n", This, pTypeAttr);
1702     free_embedded_typedesc(&pTypeAttr->tdescAlias);
1703     CoTaskMemFree(pTypeAttr);
1704 }
1705
1706 HRESULT __RPC_STUB ITypeInfo_ReleaseTypeAttr_Stub(
1707     ITypeInfo* This)
1708 {
1709     TRACE("nothing to do\n");
1710     return S_OK;
1711 }
1712
1713 void CALLBACK ITypeInfo_ReleaseFuncDesc_Proxy(
1714     ITypeInfo* This,
1715     FUNCDESC* pFuncDesc)
1716 {
1717     SHORT param;
1718     TRACE("(%p, %p)\n", This, pFuncDesc);
1719
1720     for(param = 0; param < pFuncDesc->cParams; param++)
1721         free_embedded_elemdesc(pFuncDesc->lprgelemdescParam + param);
1722     if(param)
1723         CoTaskMemFree(pFuncDesc->lprgelemdescParam);
1724
1725     free_embedded_elemdesc(&pFuncDesc->elemdescFunc);
1726
1727     if(pFuncDesc->cScodes != 0 && pFuncDesc->cScodes != -1)
1728         CoTaskMemFree(pFuncDesc->lprgscode);
1729
1730     CoTaskMemFree(pFuncDesc);
1731 }
1732
1733 HRESULT __RPC_STUB ITypeInfo_ReleaseFuncDesc_Stub(
1734     ITypeInfo* This)
1735 {
1736     TRACE("nothing to do\n");
1737     return S_OK;
1738 }
1739
1740 void CALLBACK ITypeInfo_ReleaseVarDesc_Proxy(
1741     ITypeInfo* This,
1742     VARDESC* pVarDesc)
1743 {
1744     TRACE("(%p, %p)\n", This, pVarDesc);
1745
1746     CoTaskMemFree(pVarDesc->lpstrSchema);
1747
1748     if(pVarDesc->varkind == VAR_CONST)
1749         CoTaskMemFree(pVarDesc->u.lpvarValue);
1750
1751     free_embedded_elemdesc(&pVarDesc->elemdescVar);
1752     CoTaskMemFree(pVarDesc);
1753 }
1754
1755 HRESULT __RPC_STUB ITypeInfo_ReleaseVarDesc_Stub(
1756     ITypeInfo* This)
1757 {
1758     TRACE("nothing to do\n");
1759     return S_OK;
1760 }
1761
1762
1763 /* ITypeInfo2 */
1764
1765 HRESULT CALLBACK ITypeInfo2_GetDocumentation2_Proxy(
1766     ITypeInfo2* This,
1767     MEMBERID memid,
1768     LCID lcid,
1769     BSTR* pbstrHelpString,
1770     DWORD* pdwHelpStringContext,
1771     BSTR* pbstrHelpStringDll)
1772 {
1773   FIXME("not implemented\n");
1774   return E_FAIL;
1775 }
1776
1777 HRESULT __RPC_STUB ITypeInfo2_GetDocumentation2_Stub(
1778     ITypeInfo2* This,
1779     MEMBERID memid,
1780     LCID lcid,
1781     DWORD refPtrFlags,
1782     BSTR* pbstrHelpString,
1783     DWORD* pdwHelpStringContext,
1784     BSTR* pbstrHelpStringDll)
1785 {
1786   FIXME("not implemented\n");
1787   return E_FAIL;
1788 }
1789
1790 /* ITypeLib */
1791
1792 UINT CALLBACK ITypeLib_GetTypeInfoCount_Proxy(
1793     ITypeLib* This)
1794 {
1795     UINT count = 0;
1796     TRACE("(%p)\n", This);
1797
1798     ITypeLib_RemoteGetTypeInfoCount_Proxy(This, &count);
1799     
1800     return count;
1801 }
1802
1803 HRESULT __RPC_STUB ITypeLib_GetTypeInfoCount_Stub(
1804     ITypeLib* This,
1805     UINT* pcTInfo)
1806 {
1807     TRACE("(%p, %p)\n", This, pcTInfo);
1808     *pcTInfo = ITypeLib_GetTypeInfoCount(This);
1809     return S_OK;
1810 }
1811
1812 HRESULT CALLBACK ITypeLib_GetLibAttr_Proxy(
1813     ITypeLib* This,
1814     TLIBATTR** ppTLibAttr)
1815 {
1816     CLEANLOCALSTORAGE stg;
1817     TRACE("(%p, %p)\n", This, ppTLibAttr);
1818
1819     stg.flags = 0;
1820     stg.pStorage = NULL;
1821     stg.pInterface = NULL;
1822
1823     return ITypeLib_RemoteGetLibAttr_Proxy(This, ppTLibAttr, &stg);    
1824 }
1825
1826 HRESULT __RPC_STUB ITypeLib_GetLibAttr_Stub(
1827     ITypeLib* This,
1828     LPTLIBATTR* ppTLibAttr,
1829     CLEANLOCALSTORAGE* pDummy)
1830 {
1831     HRESULT hr;
1832     TRACE("(%p, %p)\n", This, ppTLibAttr);
1833     
1834     hr = ITypeLib_GetLibAttr(This, ppTLibAttr);
1835     if(hr != S_OK)
1836         return hr;
1837
1838     pDummy->flags = CLS_LIBATTR;
1839     ITypeLib_AddRef(This);
1840     pDummy->pInterface = (IUnknown*)This;
1841     pDummy->pStorage = ppTLibAttr;
1842     return hr;
1843 }
1844
1845 HRESULT CALLBACK ITypeLib_GetDocumentation_Proxy(
1846     ITypeLib* This,
1847     INT index,
1848     BSTR* pBstrName,
1849     BSTR* pBstrDocString,
1850     DWORD* pdwHelpContext,
1851     BSTR* pBstrHelpFile)
1852 {
1853   FIXME("not implemented\n");
1854   return E_FAIL;
1855 }
1856
1857 HRESULT __RPC_STUB ITypeLib_GetDocumentation_Stub(
1858     ITypeLib* This,
1859     INT index,
1860     DWORD refPtrFlags,
1861     BSTR* pBstrName,
1862     BSTR* pBstrDocString,
1863     DWORD* pdwHelpContext,
1864     BSTR* pBstrHelpFile)
1865 {
1866   FIXME("not implemented\n");
1867   return E_FAIL;
1868 }
1869
1870 HRESULT CALLBACK ITypeLib_IsName_Proxy(
1871     ITypeLib* This,
1872     LPOLESTR szNameBuf,
1873     ULONG lHashVal,
1874     BOOL* pfName)
1875 {
1876   FIXME("not implemented\n");
1877   return E_FAIL;
1878 }
1879
1880 HRESULT __RPC_STUB ITypeLib_IsName_Stub(
1881     ITypeLib* This,
1882     LPOLESTR szNameBuf,
1883     ULONG lHashVal,
1884     BOOL* pfName,
1885     BSTR* pBstrLibName)
1886 {
1887   FIXME("not implemented\n");
1888   return E_FAIL;
1889 }
1890
1891 HRESULT CALLBACK ITypeLib_FindName_Proxy(
1892     ITypeLib* This,
1893     LPOLESTR szNameBuf,
1894     ULONG lHashVal,
1895     ITypeInfo** ppTInfo,
1896     MEMBERID* rgMemId,
1897     USHORT* pcFound)
1898 {
1899   FIXME("not implemented\n");
1900   return E_FAIL;
1901 }
1902
1903 HRESULT __RPC_STUB ITypeLib_FindName_Stub(
1904     ITypeLib* This,
1905     LPOLESTR szNameBuf,
1906     ULONG lHashVal,
1907     ITypeInfo** ppTInfo,
1908     MEMBERID* rgMemId,
1909     USHORT* pcFound,
1910     BSTR* pBstrLibName)
1911 {
1912   FIXME("not implemented\n");
1913   return E_FAIL;
1914 }
1915
1916 void CALLBACK ITypeLib_ReleaseTLibAttr_Proxy(
1917     ITypeLib* This,
1918     TLIBATTR* pTLibAttr)
1919 {
1920     TRACE("(%p, %p)\n", This, pTLibAttr);
1921     CoTaskMemFree(pTLibAttr);
1922 }
1923
1924 HRESULT __RPC_STUB ITypeLib_ReleaseTLibAttr_Stub(
1925     ITypeLib* This)
1926 {
1927     TRACE("nothing to do\n");
1928     return S_OK;
1929 }
1930
1931
1932 /* ITypeLib2 */
1933
1934 HRESULT CALLBACK ITypeLib2_GetLibStatistics_Proxy(
1935     ITypeLib2* This,
1936     ULONG* pcUniqueNames,
1937     ULONG* pcchUniqueNames)
1938 {
1939   FIXME("not implemented\n");
1940   return E_FAIL;
1941 }
1942
1943 HRESULT __RPC_STUB ITypeLib2_GetLibStatistics_Stub(
1944     ITypeLib2* This,
1945     ULONG* pcUniqueNames,
1946     ULONG* pcchUniqueNames)
1947 {
1948   FIXME("not implemented\n");
1949   return E_FAIL;
1950 }
1951
1952 HRESULT CALLBACK ITypeLib2_GetDocumentation2_Proxy(
1953     ITypeLib2* This,
1954     INT index,
1955     LCID lcid,
1956     BSTR* pbstrHelpString,
1957     DWORD* pdwHelpStringContext,
1958     BSTR* pbstrHelpStringDll)
1959 {
1960   FIXME("not implemented\n");
1961   return E_FAIL;
1962 }
1963
1964 HRESULT __RPC_STUB ITypeLib2_GetDocumentation2_Stub(
1965     ITypeLib2* This,
1966     INT index,
1967     LCID lcid,
1968     DWORD refPtrFlags,
1969     BSTR* pbstrHelpString,
1970     DWORD* pdwHelpStringContext,
1971     BSTR* pbstrHelpStringDll)
1972 {
1973   FIXME("not implemented\n");
1974   return E_FAIL;
1975 }