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