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