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