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