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