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