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