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