Fix the tests to pass when locale settings are user-overriden.
[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 NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winerror.h"
32
33 #include "ole2.h"
34 #include "oleauto.h"
35 #include "rpcproxy.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39
40 /* FIXME: not supposed to be here */
41
42 const CLSID CLSID_PSDispatch = {
43   0x20420, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
44 };
45
46 static CStdPSFactoryBuffer PSFactoryBuffer;
47
48 CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer)
49
50 extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo;
51
52 const ProxyFileInfo* OLEAUT32_ProxyFileList[] = {
53   &oaidl_ProxyFileInfo,
54   NULL
55 };
56
57 HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
58 {
59   return NdrDllGetClassObject(rclsid, riid, ppv, OLEAUT32_ProxyFileList,
60                               &CLSID_PSDispatch, &PSFactoryBuffer);
61 }
62
63 /* CLEANLOCALSTORAGE */
64 /* I'm not sure how this is supposed to work yet */
65
66 unsigned long WINAPI CLEANLOCALSTORAGE_UserSize(unsigned long *pFlags, unsigned long Start, CLEANLOCALSTORAGE *pstg)
67 {
68   return Start + sizeof(DWORD);
69 }
70
71 unsigned char * WINAPI CLEANLOCALSTORAGE_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstg)
72 {
73   *(DWORD*)Buffer = 0;
74   return Buffer + sizeof(DWORD);
75 }
76
77 unsigned char * WINAPI CLEANLOCALSTORAGE_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstr)
78 {
79   return Buffer + sizeof(DWORD);
80 }
81
82 void WINAPI CLEANLOCALSTORAGE_UserFree(unsigned long *pFlags, CLEANLOCALSTORAGE *pstr)
83 {
84 }
85
86 /* BSTR */
87
88 unsigned long WINAPI BSTR_UserSize(unsigned long *pFlags, unsigned long Start, BSTR *pstr)
89 {
90   TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr);
91   if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
92   Start += sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (SysStringLen(*pstr) - 1);
93   TRACE("returning %ld\n", Start);
94   return Start;
95 }
96
97 unsigned char * WINAPI BSTR_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr)
98 {
99   wireBSTR str = (wireBSTR)Buffer;
100
101   TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
102   if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
103   str->fFlags = 0;
104   str->clSize = SysStringLen(*pstr);
105   if (str->clSize)
106     memcpy(&str->asData, *pstr, sizeof(OLECHAR) * str->clSize);
107   return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1);
108 }
109
110 unsigned char * WINAPI BSTR_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr)
111 {
112   wireBSTR str = (wireBSTR)Buffer;
113   TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
114   if (str->clSize) {
115     SysReAllocStringLen(pstr, (OLECHAR*)&str->asData, str->clSize);
116   }
117   else if (*pstr) {
118     SysFreeString(*pstr);
119     *pstr = NULL;
120   }
121   if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
122   return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1);
123 }
124
125 void WINAPI BSTR_UserFree(unsigned long *pFlags, BSTR *pstr)
126 {
127   TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr);
128   if (*pstr) {
129     SysFreeString(*pstr);
130     *pstr = NULL;
131   }
132 }
133
134 /* VARIANT */
135 /* I'm not too sure how to do this yet */
136
137 #define VARIANT_wiresize sizeof(struct _wireVARIANT)
138
139 static unsigned wire_size(VARTYPE vt)
140 {
141   if (vt & VT_ARRAY) return 0;
142
143   switch (vt & ~VT_BYREF) {
144   case VT_EMPTY:
145   case VT_NULL:
146     return 0;
147   case VT_I1:
148   case VT_UI1:
149     return sizeof(CHAR);
150   case VT_I2:
151   case VT_UI2:
152     return sizeof(SHORT);
153   case VT_I4:
154   case VT_UI4:
155     return sizeof(LONG);
156   case VT_INT:
157   case VT_UINT:
158     return sizeof(INT);
159   case VT_R4:
160     return sizeof(FLOAT);
161   case VT_R8:
162     return sizeof(DOUBLE);
163   case VT_BOOL:
164     return sizeof(VARIANT_BOOL);
165   case VT_ERROR:
166     return sizeof(SCODE);
167   case VT_DATE:
168     return sizeof(DATE);
169   case VT_CY:
170     return sizeof(CY);
171   case VT_DECIMAL:
172     return sizeof(DECIMAL);
173   case VT_BSTR:
174   case VT_VARIANT:
175   case VT_UNKNOWN:
176   case VT_DISPATCH:
177   case VT_SAFEARRAY:
178   case VT_RECORD:
179     return 0;
180   default:
181     FIXME("unhandled VT %d\n", vt);
182     return 0;
183   }
184 }
185
186 static unsigned wire_extra(unsigned long *pFlags, VARIANT *pvar)
187 {
188   ULONG size;
189   HRESULT hr;
190
191   if (V_VT(pvar) & VT_ARRAY) {
192     FIXME("wire-size safearray\n");
193     return 0;
194   }
195   switch (V_VT(pvar)) {
196   case VT_BSTR:
197     return BSTR_UserSize(pFlags, 0, &V_BSTR(pvar));
198   case VT_BSTR | VT_BYREF:
199     return BSTR_UserSize(pFlags, 0, V_BSTRREF(pvar));
200   case VT_SAFEARRAY:
201   case VT_SAFEARRAY | VT_BYREF:
202     FIXME("wire-size safearray\n");
203     return 0;
204   case VT_VARIANT | VT_BYREF:
205     return VARIANT_UserSize(pFlags, 0, V_VARIANTREF(pvar));
206   case VT_UNKNOWN:
207   case VT_DISPATCH:
208     /* find the buffer size of the marshalled dispatch interface */
209     hr = CoGetMarshalSizeMax(&size, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
210     if (FAILED(hr)) {
211       ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%lx\n", hr);
212       return 0;
213     }
214     size += sizeof(ULONG); /* we have to store the buffersize in the stream */
215     TRACE("wire-size extra of dispatch variant is %ld\n", size);
216     return size;
217   case VT_RECORD:
218     FIXME("wire-size record\n");
219     return 0;
220   default:
221     return 0;
222   }
223 }
224
225 /* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer. returns Buffer on failure, new position otherwise */
226 static unsigned char* dispatch_variant_marshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) {
227   IStream *working; 
228   HGLOBAL working_mem;
229   void *working_memlocked;
230   unsigned char *oldpos;
231   ULONG size;
232   HRESULT hr;
233   
234   TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
235
236   oldpos = Buffer;
237   
238   /* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers.
239    * We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer.
240    * in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object,
241    * but that would be overkill here, hence this implementation. We save the size because the unmarshal
242    * code has no way to know how long the marshalled buffer is. */
243
244   size = wire_extra(pFlags, pvar);
245   
246   working_mem = GlobalAlloc(0, size);
247   if (!working_mem) return oldpos;
248
249   hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
250   if (hr != S_OK) {
251     GlobalFree(working_mem);
252     return oldpos;
253   }
254   
255   hr = CoMarshalInterface(working, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
256   if (hr != S_OK) {
257     IStream_Release(working); /* this also releases the hglobal */
258     return oldpos;
259   }
260
261   working_memlocked = GlobalLock(working_mem);
262   memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */
263   Buffer += sizeof(ULONG);
264   memcpy(Buffer, working_memlocked, size);
265   GlobalUnlock(working_mem);
266
267   IStream_Release(working);
268
269   TRACE("done, size=%ld\n", sizeof(ULONG) + size);
270   return Buffer + sizeof(ULONG) + size;
271 }
272
273 /* helper: called for VT_DISPATCH variants to unmarshal the buffer back into a dispatch variant. returns Buffer on failure, new position otherwise */
274 static unsigned char *dispatch_variant_unmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) {
275   IStream *working;
276   HGLOBAL working_mem;
277   void *working_memlocked;
278   unsigned char *oldpos;
279   ULONG size;
280   HRESULT hr;
281   
282   TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);
283
284   oldpos = Buffer;
285   
286   /* get the buffersize */
287   memcpy(&size, Buffer, sizeof(ULONG));
288   TRACE("buffersize=%ld\n", size);
289   Buffer += sizeof(ULONG);
290   
291   working_mem = GlobalAlloc(0, size);
292   if (!working_mem) return oldpos;
293
294   hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
295   if (hr != S_OK) {
296     GlobalFree(working_mem);
297     return oldpos;
298   }
299
300   working_memlocked = GlobalLock(working_mem);
301   
302   /* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */
303   memcpy(working_memlocked, Buffer, size);
304   GlobalUnlock(working_mem);
305
306   hr = CoUnmarshalInterface(working, &IID_IDispatch, (void**)&V_DISPATCH(pvar));
307   if (hr != S_OK) {
308     IStream_Release(working);
309     return oldpos;
310   }
311
312   IStream_Release(working); /* this also frees the underlying hglobal */
313
314   TRACE("done, processed=%ld bytes\n", sizeof(ULONG) + size);
315   return Buffer + sizeof(ULONG) + size;
316 }
317
318
319 unsigned long WINAPI VARIANT_UserSize(unsigned long *pFlags, unsigned long Start, VARIANT *pvar)
320 {
321   TRACE("(%lx,%ld,%p)\n", *pFlags, Start, pvar);
322   TRACE("vt=%04x\n", V_VT(pvar));
323   Start += VARIANT_wiresize + wire_extra(pFlags, pvar);
324   TRACE("returning %ld\n", Start);
325   return Start;
326 }
327
328 unsigned char * WINAPI VARIANT_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar)
329 {
330   wireVARIANT var = (wireVARIANT)Buffer;
331   unsigned size, extra;
332   unsigned char *Pos = Buffer + VARIANT_wiresize;
333
334   TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar);
335   TRACE("vt=%04x\n", V_VT(pvar));
336
337   memset(var, 0, sizeof(*var));
338   var->clSize = sizeof(*var);
339   var->vt = pvar->n1.n2.vt;
340
341   var->rpcReserved = var->vt;
342   if ((var->vt & VT_ARRAY) ||
343       ((var->vt & VT_TYPEMASK) == VT_SAFEARRAY))
344     var->vt = VT_ARRAY | (var->vt & VT_BYREF);
345
346   if (var->vt == VT_DECIMAL) {
347     /* special case because decVal is on a different level */
348     var->u.decVal = pvar->n1.decVal;
349     return Pos;
350   }
351
352   size = wire_size(V_VT(pvar));
353   extra = wire_extra(pFlags, pvar);
354   var->wReserved1 = pvar->n1.n2.wReserved1;
355   var->wReserved2 = pvar->n1.n2.wReserved2;
356   var->wReserved3 = pvar->n1.n2.wReserved3;
357   if (size) {
358     if (var->vt & VT_BYREF)
359       memcpy(&var->u.cVal, pvar->n1.n2.n3.byref, size);
360     else
361       memcpy(&var->u.cVal, &pvar->n1.n2.n3, size);
362   }
363   if (!extra) return Pos;
364
365   switch (var->vt) {
366   case VT_BSTR:
367     Pos = BSTR_UserMarshal(pFlags, Pos, &V_BSTR(pvar));
368     break;
369   case VT_BSTR | VT_BYREF:
370     Pos = BSTR_UserMarshal(pFlags, Pos, V_BSTRREF(pvar));
371     break;
372   case VT_VARIANT | VT_BYREF:
373     Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar));
374     break;
375   case VT_DISPATCH | VT_BYREF:
376     FIXME("handle DISPATCH by ref\n");
377     break;
378   case VT_DISPATCH:
379     /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
380     Pos = dispatch_variant_marshal(pFlags, Pos, pvar);
381     break;
382   case VT_RECORD:
383     FIXME("handle BRECORD by val\n");
384     break;
385   case VT_RECORD | VT_BYREF:
386     FIXME("handle BRECORD by ref\n");
387     break;
388   default:
389     FIXME("handle unknown complex type\n");
390     break;
391   }
392   var->clSize = Pos - Buffer;
393   TRACE("marshalled size=%ld\n", var->clSize);
394   return Pos;
395 }
396
397 unsigned char * WINAPI VARIANT_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar)
398 {
399   wireVARIANT var = (wireVARIANT)Buffer;
400   unsigned size;
401   unsigned char *Pos = Buffer + VARIANT_wiresize;
402
403   TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar);
404   VariantInit(pvar);
405   pvar->n1.n2.vt = var->rpcReserved;
406   TRACE("marshalled: clSize=%ld, vt=%04x\n", var->clSize, var->vt);
407   TRACE("vt=%04x\n", V_VT(pvar));
408   TRACE("reserved: %d, %d, %d\n", var->wReserved1, var->wReserved2, var->wReserved3);
409   TRACE("val: %ld\n", var->u.lVal);
410
411   if (var->vt == VT_DECIMAL) {
412     /* special case because decVal is on a different level */
413     pvar->n1.decVal = var->u.decVal;
414     return Pos;
415   }
416
417   size = wire_size(V_VT(pvar));
418   pvar->n1.n2.wReserved1 = var->wReserved1;
419   pvar->n1.n2.wReserved2 = var->wReserved2;
420   pvar->n1.n2.wReserved3 = var->wReserved3;
421   if (size) {
422     if (var->vt & VT_BYREF) {
423       pvar->n1.n2.n3.byref = CoTaskMemAlloc(size);
424       memcpy(pvar->n1.n2.n3.byref, &var->u.cVal, size);
425     }
426     else
427       memcpy(&pvar->n1.n2.n3, &var->u.cVal, size);
428   }
429   if (var->clSize <= VARIANT_wiresize) return Pos;
430
431   switch (var->vt) {
432   case VT_BSTR:
433     Pos = BSTR_UserUnmarshal(pFlags, Pos, &V_BSTR(pvar));
434     break;
435   case VT_BSTR | VT_BYREF:
436     pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(BSTR));
437     *(BSTR*)pvar->n1.n2.n3.byref = NULL;
438     Pos = BSTR_UserUnmarshal(pFlags, Pos, V_BSTRREF(pvar));
439     break;
440   case VT_VARIANT | VT_BYREF:
441     pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(VARIANT));
442     Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar));
443     break;
444   case VT_RECORD:
445     FIXME("handle BRECORD by val\n");
446     break;
447   case VT_RECORD | VT_BYREF:
448     FIXME("handle BRECORD by ref\n");
449     break;
450   case VT_DISPATCH:
451     Pos = dispatch_variant_unmarshal(pFlags, Pos, pvar);
452     break;
453   case VT_DISPATCH | VT_BYREF:
454     FIXME("handle DISPATCH by ref\n");
455   default:
456     FIXME("handle unknown complex type\n");
457     break;
458   }
459   if (Pos != Buffer + var->clSize) {
460     ERR("size difference during unmarshal\n");
461   }
462   return Buffer + var->clSize;
463 }
464
465 void WINAPI VARIANT_UserFree(unsigned long *pFlags, VARIANT *pvar)
466 {
467   VARTYPE vt = V_VT(pvar);
468   PVOID ref = NULL;
469
470   TRACE("(%lx,%p)\n", *pFlags, pvar);
471   TRACE("vt=%04x\n", V_VT(pvar));
472
473   if (vt & VT_BYREF) ref = pvar->n1.n2.n3.byref;
474
475   VariantClear(pvar);
476   if (!ref) return;
477
478   switch (vt) {
479   case VT_BSTR | VT_BYREF:
480     BSTR_UserFree(pFlags, ref);
481     break;
482   case VT_VARIANT | VT_BYREF:
483     VARIANT_UserFree(pFlags, ref);
484     break;
485   case VT_RECORD | VT_BYREF:
486     FIXME("handle BRECORD by ref\n");
487     break;
488   default:
489     FIXME("handle unknown complex type\n");
490     break;
491   }
492
493   CoTaskMemFree(ref);
494 }
495
496 /* IDispatch */
497 /* exactly how Invoke is marshalled is not very clear to me yet,
498  * but the way I've done it seems to work for me */
499
500 HRESULT CALLBACK IDispatch_Invoke_Proxy(
501     IDispatch* This,
502     DISPID dispIdMember,
503     REFIID riid,
504     LCID lcid,
505     WORD wFlags,
506     DISPPARAMS* pDispParams,
507     VARIANT* pVarResult,
508     EXCEPINFO* pExcepInfo,
509     UINT* puArgErr)
510 {
511   HRESULT hr;
512   VARIANT VarResult;
513   UINT* rgVarRefIdx = NULL;
514   VARIANTARG* rgVarRef = NULL;
515   UINT u, cVarRef;
516
517   TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This,
518         dispIdMember, debugstr_guid(riid),
519         lcid, wFlags, pDispParams, pVarResult,
520         pExcepInfo, puArgErr);
521
522   /* [out] args can't be null, use dummy vars if needed */
523   if (!pVarResult) pVarResult = &VarResult;
524
525   /* count by-ref args */
526   for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) {
527     VARIANTARG* arg = &pDispParams->rgvarg[u];
528     if (V_VT(arg) & VT_BYREF) {
529       cVarRef++;
530     }
531   }
532   if (cVarRef) {
533     rgVarRefIdx = CoTaskMemAlloc(sizeof(UINT)*cVarRef);
534     rgVarRef = CoTaskMemAlloc(sizeof(VARIANTARG)*cVarRef);
535     /* make list of by-ref args */
536     for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) {
537       VARIANTARG* arg = &pDispParams->rgvarg[u];
538       if (V_VT(arg) & VT_BYREF) {
539         rgVarRefIdx[cVarRef] = u;
540         VariantInit(&rgVarRef[cVarRef]);
541         cVarRef++;
542       }
543     }
544   } else {
545     /* [out] args still can't be null,
546      * but we can point these anywhere in this case,
547      * since they won't be written to when cVarRef is 0 */
548     rgVarRefIdx = puArgErr;
549     rgVarRef = pVarResult;
550   }
551   TRACE("passed by ref: %d args\n", cVarRef);
552   hr = IDispatch_RemoteInvoke_Proxy(This,
553                                     dispIdMember,
554                                     riid,
555                                     lcid,
556                                     wFlags,
557                                     pDispParams,
558                                     pVarResult,
559                                     pExcepInfo,
560                                     puArgErr,
561                                     cVarRef,
562                                     rgVarRefIdx,
563                                     rgVarRef);
564   if (cVarRef) {
565     for (u=0; u<cVarRef; u++) {
566       unsigned i = rgVarRefIdx[u];
567       VariantCopy(&pDispParams->rgvarg[i],
568                   &rgVarRef[u]);
569       VariantClear(&rgVarRef[u]);
570     }
571     CoTaskMemFree(rgVarRef);
572     CoTaskMemFree(rgVarRefIdx);
573   }
574   return hr;
575 }
576
577 HRESULT __RPC_STUB IDispatch_Invoke_Stub(
578     IDispatch* This,
579     DISPID dispIdMember,
580     REFIID riid,
581     LCID lcid,
582     DWORD dwFlags,
583     DISPPARAMS* pDispParams,
584     VARIANT* pVarResult,
585     EXCEPINFO* pExcepInfo,
586     UINT* pArgErr,
587     UINT cVarRef,
588     UINT* rgVarRefIdx,
589     VARIANTARG* rgVarRef)
590 {
591   HRESULT hr;
592   VARIANTARG *rgvarg, *arg;
593   UINT u;
594
595   /* let the real Invoke operate on a copy of the in parameters,
596    * so we don't risk losing pointers to allocated memory */
597   rgvarg = pDispParams->rgvarg;
598   arg = CoTaskMemAlloc(sizeof(VARIANTARG)*pDispParams->cArgs);
599   for (u=0; u<pDispParams->cArgs; u++) {
600     VariantInit(&arg[u]);
601     VariantCopy(&arg[u], &rgvarg[u]);
602   }
603   pDispParams->rgvarg = arg;
604
605   /* initialize out parameters, so that they can be marshalled
606    * in case the real Invoke doesn't initialize them */
607   VariantInit(pVarResult);
608   memset(pExcepInfo, 0, sizeof(*pExcepInfo));
609   *pArgErr = 0;
610
611   hr = IDispatch_Invoke(This,
612                         dispIdMember,
613                         riid,
614                         lcid,
615                         dwFlags,
616                         pDispParams,
617                         pVarResult,
618                         pExcepInfo,
619                         pArgErr);
620
621   /* copy ref args to out list */
622   for (u=0; u<cVarRef; u++) {
623     unsigned i = rgVarRefIdx[u];
624     VariantInit(&rgVarRef[u]);
625     VariantCopy(&rgVarRef[u], &arg[i]);
626     /* clear original if equal, to avoid double-free */
627     if (V_BYREF(&rgVarRef[u]) == V_BYREF(&rgvarg[i]))
628       VariantClear(&rgvarg[i]);
629   }
630   /* clear the duplicate argument list */
631   for (u=0; u<pDispParams->cArgs; u++) {
632     VariantClear(&arg[u]);
633   }
634   pDispParams->rgvarg = rgvarg;
635   CoTaskMemFree(arg);
636
637   return hr;
638 }
639
640 /* IEnumVARIANT */
641
642 HRESULT CALLBACK IEnumVARIANT_Next_Proxy(
643     IEnumVARIANT* This,
644     ULONG celt,
645     VARIANT* rgVar,
646     ULONG* pCeltFetched)
647 {
648   ULONG fetched;
649   if (!pCeltFetched)
650     pCeltFetched = &fetched;
651   return IEnumVARIANT_RemoteNext_Proxy(This,
652                                        celt,
653                                        rgVar,
654                                        pCeltFetched);
655 }
656
657 HRESULT __RPC_STUB IEnumVARIANT_Next_Stub(
658     IEnumVARIANT* This,
659     ULONG celt,
660     VARIANT* rgVar,
661     ULONG* pCeltFetched)
662 {
663   HRESULT hr;
664   *pCeltFetched = 0;
665   hr = IEnumVARIANT_Next(This,
666                          celt,
667                          rgVar,
668                          pCeltFetched);
669   if (hr == S_OK) *pCeltFetched = celt;
670   return hr;
671 }
672
673 /* ITypeComp */
674
675 HRESULT CALLBACK ITypeComp_Bind_Proxy(
676     ITypeComp* This,
677     LPOLESTR szName,
678     ULONG lHashVal,
679     WORD wFlags,
680     ITypeInfo** ppTInfo,
681     DESCKIND* pDescKind,
682     BINDPTR* pBindPtr)
683 {
684   FIXME("not implemented\n");
685   return E_FAIL;
686 }
687
688 HRESULT __RPC_STUB ITypeComp_Bind_Stub(
689     ITypeComp* This,
690     LPOLESTR szName,
691     ULONG lHashVal,
692     WORD wFlags,
693     ITypeInfo** ppTInfo,
694     DESCKIND* pDescKind,
695     LPFUNCDESC* ppFuncDesc,
696     LPVARDESC* ppVarDesc,
697     ITypeComp** ppTypeComp,
698     CLEANLOCALSTORAGE* pDummy)
699 {
700   FIXME("not implemented\n");
701   return E_FAIL;
702 }
703
704 HRESULT CALLBACK ITypeComp_BindType_Proxy(
705     ITypeComp* This,
706     LPOLESTR szName,
707     ULONG lHashVal,
708     ITypeInfo** ppTInfo,
709     ITypeComp** ppTComp)
710 {
711   FIXME("not implemented\n");
712   return E_FAIL;
713 }
714
715 HRESULT __RPC_STUB ITypeComp_BindType_Stub(
716     ITypeComp* This,
717     LPOLESTR szName,
718     ULONG lHashVal,
719     ITypeInfo** ppTInfo)
720 {
721   FIXME("not implemented\n");
722   return E_FAIL;
723 }
724
725 /* ITypeInfo */
726
727 HRESULT CALLBACK ITypeInfo_GetTypeAttr_Proxy(
728     ITypeInfo* This,
729     TYPEATTR** ppTypeAttr)
730 {
731   FIXME("not implemented\n");
732   return E_FAIL;
733 }
734
735 HRESULT __RPC_STUB ITypeInfo_GetTypeAttr_Stub(
736     ITypeInfo* This,
737     LPTYPEATTR* ppTypeAttr,
738     CLEANLOCALSTORAGE* pDummy)
739 {
740   FIXME("not implemented\n");
741   return E_FAIL;
742 }
743
744 HRESULT CALLBACK ITypeInfo_GetFuncDesc_Proxy(
745     ITypeInfo* This,
746     UINT index,
747     FUNCDESC** ppFuncDesc)
748 {
749   FIXME("not implemented\n");
750   return E_FAIL;
751 }
752
753 HRESULT __RPC_STUB ITypeInfo_GetFuncDesc_Stub(
754     ITypeInfo* This,
755     UINT index,
756     LPFUNCDESC* ppFuncDesc,
757     CLEANLOCALSTORAGE* pDummy)
758 {
759   FIXME("not implemented\n");
760   return E_FAIL;
761 }
762
763 HRESULT CALLBACK ITypeInfo_GetVarDesc_Proxy(
764     ITypeInfo* This,
765     UINT index,
766     VARDESC** ppVarDesc)
767 {
768   FIXME("not implemented\n");
769   return E_FAIL;
770 }
771
772 HRESULT __RPC_STUB ITypeInfo_GetVarDesc_Stub(
773     ITypeInfo* This,
774     UINT index,
775     LPVARDESC* ppVarDesc,
776     CLEANLOCALSTORAGE* pDummy)
777 {
778   FIXME("not implemented\n");
779   return E_FAIL;
780 }
781
782 HRESULT CALLBACK ITypeInfo_GetNames_Proxy(
783     ITypeInfo* This,
784     MEMBERID memid,
785     BSTR* rgBstrNames,
786     UINT cMaxNames,
787     UINT* pcNames)
788 {
789   FIXME("not implemented\n");
790   return E_FAIL;
791 }
792
793 HRESULT __RPC_STUB ITypeInfo_GetNames_Stub(
794     ITypeInfo* This,
795     MEMBERID memid,
796     BSTR* rgBstrNames,
797     UINT cMaxNames,
798     UINT* pcNames)
799 {
800   FIXME("not implemented\n");
801   return E_FAIL;
802 }
803
804 HRESULT CALLBACK ITypeInfo_GetIDsOfNames_Proxy(
805     ITypeInfo* This,
806     LPOLESTR* rgszNames,
807     UINT cNames,
808     MEMBERID* pMemId)
809 {
810   FIXME("not implemented\n");
811   return E_FAIL;
812 }
813
814 HRESULT __RPC_STUB ITypeInfo_GetIDsOfNames_Stub(
815     ITypeInfo* This)
816 {
817   FIXME("not implemented\n");
818   return E_FAIL;
819 }
820
821 HRESULT CALLBACK ITypeInfo_Invoke_Proxy(
822     ITypeInfo* This,
823     PVOID pvInstance,
824     MEMBERID memid,
825     WORD wFlags,
826     DISPPARAMS* pDispParams,
827     VARIANT* pVarResult,
828     EXCEPINFO* pExcepInfo,
829     UINT* puArgErr)
830 {
831   FIXME("not implemented\n");
832   return E_FAIL;
833 }
834
835 HRESULT __RPC_STUB ITypeInfo_Invoke_Stub(
836     ITypeInfo* This)
837 {
838   FIXME("not implemented\n");
839   return E_FAIL;
840 }
841
842 HRESULT CALLBACK ITypeInfo_GetDocumentation_Proxy(
843     ITypeInfo* This,
844     MEMBERID memid,
845     BSTR* pBstrName,
846     BSTR* pBstrDocString,
847     DWORD* pdwHelpContext,
848     BSTR* pBstrHelpFile)
849 {
850   FIXME("not implemented\n");
851   return E_FAIL;
852 }
853
854 HRESULT __RPC_STUB ITypeInfo_GetDocumentation_Stub(
855     ITypeInfo* This,
856     MEMBERID memid,
857     DWORD refPtrFlags,
858     BSTR* pBstrName,
859     BSTR* pBstrDocString,
860     DWORD* pdwHelpContext,
861     BSTR* pBstrHelpFile)
862 {
863   FIXME("not implemented\n");
864   return E_FAIL;
865 }
866
867 HRESULT CALLBACK ITypeInfo_GetDllEntry_Proxy(
868     ITypeInfo* This,
869     MEMBERID memid,
870     INVOKEKIND invKind,
871     BSTR* pBstrDllName,
872     BSTR* pBstrName,
873     WORD* pwOrdinal)
874 {
875   FIXME("not implemented\n");
876   return E_FAIL;
877 }
878
879 HRESULT __RPC_STUB ITypeInfo_GetDllEntry_Stub(
880     ITypeInfo* This,
881     MEMBERID memid,
882     INVOKEKIND invKind,
883     DWORD refPtrFlags,
884     BSTR* pBstrDllName,
885     BSTR* pBstrName,
886     WORD* pwOrdinal)
887 {
888   FIXME("not implemented\n");
889   return E_FAIL;
890 }
891
892 HRESULT CALLBACK ITypeInfo_AddressOfMember_Proxy(
893     ITypeInfo* This,
894     MEMBERID memid,
895     INVOKEKIND invKind,
896     PVOID* ppv)
897 {
898   FIXME("not implemented\n");
899   return E_FAIL;
900 }
901
902 HRESULT __RPC_STUB ITypeInfo_AddressOfMember_Stub(
903     ITypeInfo* This)
904 {
905   FIXME("not implemented\n");
906   return E_FAIL;
907 }
908
909 HRESULT CALLBACK ITypeInfo_CreateInstance_Proxy(
910     ITypeInfo* This,
911     IUnknown* pUnkOuter,
912     REFIID riid,
913     PVOID* ppvObj)
914 {
915   FIXME("not implemented\n");
916   return E_FAIL;
917 }
918
919 HRESULT __RPC_STUB ITypeInfo_CreateInstance_Stub(
920     ITypeInfo* This,
921     REFIID riid,
922     IUnknown** ppvObj)
923 {
924   FIXME("not implemented\n");
925   return E_FAIL;
926 }
927
928 HRESULT CALLBACK ITypeInfo_GetContainingTypeLib_Proxy(
929     ITypeInfo* This,
930     ITypeLib** ppTLib,
931     UINT* pIndex)
932 {
933   FIXME("not implemented\n");
934   return E_FAIL;
935 }
936
937 HRESULT __RPC_STUB ITypeInfo_GetContainingTypeLib_Stub(
938     ITypeInfo* This,
939     ITypeLib** ppTLib,
940     UINT* pIndex)
941 {
942   FIXME("not implemented\n");
943   return E_FAIL;
944 }
945
946 void CALLBACK ITypeInfo_ReleaseTypeAttr_Proxy(
947     ITypeInfo* This,
948     TYPEATTR* pTypeAttr)
949 {
950   FIXME("not implemented\n");
951 }
952
953 HRESULT __RPC_STUB ITypeInfo_ReleaseTypeAttr_Stub(
954     ITypeInfo* This)
955 {
956   FIXME("not implemented\n");
957   return E_FAIL;
958 }
959
960 void CALLBACK ITypeInfo_ReleaseFuncDesc_Proxy(
961     ITypeInfo* This,
962     FUNCDESC* pFuncDesc)
963 {
964   FIXME("not implemented\n");
965 }
966
967 HRESULT __RPC_STUB ITypeInfo_ReleaseFuncDesc_Stub(
968     ITypeInfo* This)
969 {
970   FIXME("not implemented\n");
971   return E_FAIL;
972 }
973
974 void CALLBACK ITypeInfo_ReleaseVarDesc_Proxy(
975     ITypeInfo* This,
976     VARDESC* pVarDesc)
977 {
978   FIXME("not implemented\n");
979 }
980
981 HRESULT __RPC_STUB ITypeInfo_ReleaseVarDesc_Stub(
982     ITypeInfo* This)
983 {
984   FIXME("not implemented\n");
985   return E_FAIL;
986 }
987
988
989 /* ITypeInfo2 */
990
991 HRESULT CALLBACK ITypeInfo2_GetDocumentation2_Proxy(
992     ITypeInfo2* This,
993     MEMBERID memid,
994     LCID lcid,
995     BSTR* pbstrHelpString,
996     DWORD* pdwHelpStringContext,
997     BSTR* pbstrHelpStringDll)
998 {
999   FIXME("not implemented\n");
1000   return E_FAIL;
1001 }
1002
1003 HRESULT __RPC_STUB ITypeInfo2_GetDocumentation2_Stub(
1004     ITypeInfo2* This,
1005     MEMBERID memid,
1006     LCID lcid,
1007     DWORD refPtrFlags,
1008     BSTR* pbstrHelpString,
1009     DWORD* pdwHelpStringContext,
1010     BSTR* pbstrHelpStringDll)
1011 {
1012   FIXME("not implemented\n");
1013   return E_FAIL;
1014 }
1015
1016 /* ITypeLib */
1017
1018 UINT CALLBACK ITypeLib_GetTypeInfoCount_Proxy(
1019     ITypeLib* This)
1020 {
1021   FIXME("not implemented\n");
1022   return E_FAIL;
1023 }
1024
1025 HRESULT __RPC_STUB ITypeLib_GetTypeInfoCount_Stub(
1026     ITypeLib* This,
1027     UINT* pcTInfo)
1028 {
1029   FIXME("not implemented\n");
1030   return E_FAIL;
1031 }
1032
1033 HRESULT CALLBACK ITypeLib_GetLibAttr_Proxy(
1034     ITypeLib* This,
1035     TLIBATTR** ppTLibAttr)
1036 {
1037   FIXME("not implemented\n");
1038   return E_FAIL;
1039 }
1040
1041 HRESULT __RPC_STUB ITypeLib_GetLibAttr_Stub(
1042     ITypeLib* This,
1043     LPTLIBATTR* ppTLibAttr,
1044     CLEANLOCALSTORAGE* pDummy)
1045 {
1046   FIXME("not implemented\n");
1047   return E_FAIL;
1048 }
1049
1050 HRESULT CALLBACK ITypeLib_GetDocumentation_Proxy(
1051     ITypeLib* This,
1052     INT index,
1053     BSTR* pBstrName,
1054     BSTR* pBstrDocString,
1055     DWORD* pdwHelpContext,
1056     BSTR* pBstrHelpFile)
1057 {
1058   FIXME("not implemented\n");
1059   return E_FAIL;
1060 }
1061
1062 HRESULT __RPC_STUB ITypeLib_GetDocumentation_Stub(
1063     ITypeLib* This,
1064     INT index,
1065     DWORD refPtrFlags,
1066     BSTR* pBstrName,
1067     BSTR* pBstrDocString,
1068     DWORD* pdwHelpContext,
1069     BSTR* pBstrHelpFile)
1070 {
1071   FIXME("not implemented\n");
1072   return E_FAIL;
1073 }
1074
1075 HRESULT CALLBACK ITypeLib_IsName_Proxy(
1076     ITypeLib* This,
1077     LPOLESTR szNameBuf,
1078     ULONG lHashVal,
1079     BOOL* pfName)
1080 {
1081   FIXME("not implemented\n");
1082   return E_FAIL;
1083 }
1084
1085 HRESULT __RPC_STUB ITypeLib_IsName_Stub(
1086     ITypeLib* This,
1087     LPOLESTR szNameBuf,
1088     ULONG lHashVal,
1089     BOOL* pfName,
1090     BSTR* pBstrLibName)
1091 {
1092   FIXME("not implemented\n");
1093   return E_FAIL;
1094 }
1095
1096 HRESULT CALLBACK ITypeLib_FindName_Proxy(
1097     ITypeLib* This,
1098     LPOLESTR szNameBuf,
1099     ULONG lHashVal,
1100     ITypeInfo** ppTInfo,
1101     MEMBERID* rgMemId,
1102     USHORT* pcFound)
1103 {
1104   FIXME("not implemented\n");
1105   return E_FAIL;
1106 }
1107
1108 HRESULT __RPC_STUB ITypeLib_FindName_Stub(
1109     ITypeLib* This,
1110     LPOLESTR szNameBuf,
1111     ULONG lHashVal,
1112     ITypeInfo** ppTInfo,
1113     MEMBERID* rgMemId,
1114     USHORT* pcFound,
1115     BSTR* pBstrLibName)
1116 {
1117   FIXME("not implemented\n");
1118   return E_FAIL;
1119 }
1120
1121 void CALLBACK ITypeLib_ReleaseTLibAttr_Proxy(
1122     ITypeLib* This,
1123     TLIBATTR* pTLibAttr)
1124 {
1125   FIXME("not implemented\n");
1126 }
1127
1128 HRESULT __RPC_STUB ITypeLib_ReleaseTLibAttr_Stub(
1129     ITypeLib* This)
1130 {
1131   FIXME("not implemented\n");
1132   return E_FAIL;
1133 }
1134
1135
1136 /* ITypeLib2 */
1137
1138 HRESULT CALLBACK ITypeLib2_GetLibStatistics_Proxy(
1139     ITypeLib2* This,
1140     ULONG* pcUniqueNames,
1141     ULONG* pcchUniqueNames)
1142 {
1143   FIXME("not implemented\n");
1144   return E_FAIL;
1145 }
1146
1147 HRESULT __RPC_STUB ITypeLib2_GetLibStatistics_Stub(
1148     ITypeLib2* This,
1149     ULONG* pcUniqueNames,
1150     ULONG* pcchUniqueNames)
1151 {
1152   FIXME("not implemented\n");
1153   return E_FAIL;
1154 }
1155
1156 HRESULT CALLBACK ITypeLib2_GetDocumentation2_Proxy(
1157     ITypeLib2* This,
1158     INT index,
1159     LCID lcid,
1160     BSTR* pbstrHelpString,
1161     DWORD* pdwHelpStringContext,
1162     BSTR* pbstrHelpStringDll)
1163 {
1164   FIXME("not implemented\n");
1165   return E_FAIL;
1166 }
1167
1168 HRESULT __RPC_STUB ITypeLib2_GetDocumentation2_Stub(
1169     ITypeLib2* This,
1170     INT index,
1171     LCID lcid,
1172     DWORD refPtrFlags,
1173     BSTR* pbstrHelpString,
1174     DWORD* pdwHelpStringContext,
1175     BSTR* pbstrHelpStringDll)
1176 {
1177   FIXME("not implemented\n");
1178   return E_FAIL;
1179 }