dispex: Implement proxy and stub for IDispatchEx_InvokeEx.
[wine] / dlls / dispex / usrmarshal.c
1 /*
2  *    Misc marshaling routinues
3  *
4  * Copyright 2010 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21 #include <string.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "objbase.h"
33 #include "oleauto.h"
34 #include "dispex.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39
40 HRESULT CALLBACK IDispatchEx_InvokeEx_Proxy(IDispatchEx* This, DISPID id, LCID lcid, WORD wFlags,
41                                             DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei,
42                                             IServiceProvider *pspCaller)
43 {
44     HRESULT hr;
45     VARIANT result;
46     EXCEPINFO excep_info;
47     UINT byref_args, arg;
48     VARIANT dummy_arg, *ref_arg = &dummy_arg, *copy_arg, *orig_arg = NULL;
49     UINT *ref_idx = NULL;
50
51     TRACE("(%p)->(%08x, %04x, %04x, %p, %p, %p, %p)\n", This, id, lcid, wFlags,
52           pdp, pvarRes, pei, pspCaller);
53
54     if(!pvarRes) pvarRes = &result;
55     if(!pei) pei = &excep_info;
56
57     for(arg = 0, byref_args = 0; arg < pdp->cArgs; arg++)
58         if(V_ISBYREF(pdp->rgvarg + arg)) byref_args++;
59
60     if(byref_args)
61     {
62         DWORD size = pdp->cArgs * sizeof(VARIANT) +
63             byref_args * (sizeof(VARIANT) + sizeof(UINT));
64
65         copy_arg = CoTaskMemAlloc(size);
66         if(!copy_arg) return E_OUTOFMEMORY;
67
68         ref_arg = copy_arg + pdp->cArgs;
69         ref_idx = (UINT*)(ref_arg + byref_args);
70
71         /* copy the byref args to ref_arg[], the others go to copy_arg[] */
72         for(arg = 0, byref_args = 0; arg < pdp->cArgs; arg++)
73         {
74             if(V_ISBYREF(pdp->rgvarg + arg))
75             {
76                 ref_arg[byref_args] = pdp->rgvarg[arg];
77                 ref_idx[byref_args] = arg;
78                 VariantInit(copy_arg + arg);
79                 byref_args++;
80             }
81             else
82                 copy_arg[arg] = pdp->rgvarg[arg];
83         }
84
85         orig_arg = pdp->rgvarg;
86         pdp->rgvarg = copy_arg;
87     }
88
89     hr = IDispatchEx_RemoteInvokeEx_Proxy(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller,
90                                           byref_args, ref_idx, ref_arg);
91
92     if(byref_args)
93     {
94         CoTaskMemFree(pdp->rgvarg);
95         pdp->rgvarg = orig_arg;
96     }
97
98     if(pvarRes == &result) VariantClear(pvarRes);
99     if(pei == &excep_info)
100     {
101         SysFreeString(pei->bstrSource);
102         SysFreeString(pei->bstrDescription);
103         SysFreeString(pei->bstrHelpFile);
104     }
105
106     return hr;
107 }
108
109 HRESULT __RPC_STUB IDispatchEx_InvokeEx_Stub(IDispatchEx* This, DISPID id, LCID lcid, DWORD dwFlags,
110                                              DISPPARAMS *pdp, VARIANT *result, EXCEPINFO *pei,
111                                              IServiceProvider *pspCaller, UINT byref_args,
112                                              UINT *ref_idx, VARIANT *ref_arg)
113 {
114     HRESULT hr;
115     UINT arg;
116
117     TRACE("(%p)->(%08x, %04x, %08x, %p, %p, %p, %p, %d, %p, %p)\n", This, id, lcid, dwFlags,
118           pdp, result, pei, pspCaller, byref_args, ref_idx, ref_arg);
119
120     VariantInit(result);
121     memset(pei, 0, sizeof(*pei));
122
123     for(arg = 0; arg < byref_args; arg++)
124         pdp->rgvarg[ref_idx[arg]] = ref_arg[arg];
125
126     hr = IDispatchEx_InvokeEx(This, id, lcid, dwFlags, pdp, result, pei, pspCaller);
127
128     for(arg = 0; arg < byref_args; arg++)
129         VariantInit(pdp->rgvarg + ref_idx[arg]);
130
131     return hr;
132 }