winspool/tests: Add tests for GetFormA().
[wine.git] / dlls / dispex / usrmarshal.c
blob6e3c7239f164e5ef01d5d49a861dc4cc9ed83ae2
1 /*
2 * Misc marshaling routines
4 * Copyright 2010 Huw Davies
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.
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.
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
20 #include <stdarg.h>
21 #include <string.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "objbase.h"
31 #include "oleauto.h"
32 #include "dispex.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 #define NULL_RESULT 0x20000
39 #define NULL_EXCEPINFO 0x40000
41 HRESULT CALLBACK IDispatchEx_InvokeEx_Proxy(IDispatchEx* This, DISPID id, LCID lcid, WORD wFlags,
42 DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei,
43 IServiceProvider *pspCaller)
45 HRESULT hr;
46 VARIANT result;
47 EXCEPINFO excep_info;
48 UINT byref_args, arg, dummy_idx;
49 VARIANT dummy_arg, *ref_arg = &dummy_arg, *copy_arg, *orig_arg = NULL;
50 UINT *ref_idx = &dummy_idx;
51 DWORD dword_flags = wFlags & 0xf;
53 TRACE("(%p)->(%08x, %04x, %04x, %p, %p, %p, %p)\n", This, id, lcid, wFlags,
54 pdp, pvarRes, pei, pspCaller);
56 if(!pvarRes)
58 pvarRes = &result;
59 dword_flags |= NULL_RESULT;
62 if(!pei)
64 pei = &excep_info;
65 dword_flags |= NULL_EXCEPINFO;
68 for(arg = 0, byref_args = 0; arg < pdp->cArgs; arg++)
69 if(V_ISBYREF(pdp->rgvarg + arg)) byref_args++;
71 if(byref_args)
73 DWORD size = pdp->cArgs * sizeof(VARIANT) +
74 byref_args * (sizeof(VARIANT) + sizeof(UINT));
76 copy_arg = CoTaskMemAlloc(size);
77 if(!copy_arg) return E_OUTOFMEMORY;
79 ref_arg = copy_arg + pdp->cArgs;
80 ref_idx = (UINT*)(ref_arg + byref_args);
82 /* copy the byref args to ref_arg[], the others go to copy_arg[] */
83 for(arg = 0, byref_args = 0; arg < pdp->cArgs; arg++)
85 if(V_ISBYREF(pdp->rgvarg + arg))
87 ref_arg[byref_args] = pdp->rgvarg[arg];
88 ref_idx[byref_args] = arg;
89 VariantInit(copy_arg + arg);
90 byref_args++;
92 else
93 copy_arg[arg] = pdp->rgvarg[arg];
96 orig_arg = pdp->rgvarg;
97 pdp->rgvarg = copy_arg;
100 hr = IDispatchEx_RemoteInvokeEx_Proxy(This, id, lcid, dword_flags, pdp, pvarRes, pei, pspCaller,
101 byref_args, ref_idx, ref_arg);
103 if(byref_args)
105 CoTaskMemFree(pdp->rgvarg);
106 pdp->rgvarg = orig_arg;
109 return hr;
112 HRESULT __RPC_STUB IDispatchEx_InvokeEx_Stub(IDispatchEx* This, DISPID id, LCID lcid, DWORD dwFlags,
113 DISPPARAMS *pdp, VARIANT *result, EXCEPINFO *pei,
114 IServiceProvider *pspCaller, UINT byref_args,
115 UINT *ref_idx, VARIANT *ref_arg)
117 HRESULT hr;
118 UINT arg;
119 VARTYPE *vt_list = NULL;
121 TRACE("(%p)->(%08x, %04x, %08x, %p, %p, %p, %p, %d, %p, %p)\n", This, id, lcid, dwFlags,
122 pdp, result, pei, pspCaller, byref_args, ref_idx, ref_arg);
124 VariantInit(result);
125 memset(pei, 0, sizeof(*pei));
127 for(arg = 0; arg < byref_args; arg++)
128 pdp->rgvarg[ref_idx[arg]] = ref_arg[arg];
130 if(dwFlags & NULL_RESULT) result = NULL;
131 if(dwFlags & NULL_EXCEPINFO) pei = NULL;
133 /* Create an array of the original VTs to check that the function doesn't change
134 any on return. */
135 if(byref_args)
137 vt_list = HeapAlloc(GetProcessHeap(), 0, pdp->cArgs * sizeof(vt_list[0]));
138 if(!vt_list) return E_OUTOFMEMORY;
139 for(arg = 0; arg < pdp->cArgs; arg++)
140 vt_list[arg] = V_VT(pdp->rgvarg + arg);
143 hr = IDispatchEx_InvokeEx(This, id, lcid, dwFlags & 0xffff, pdp, result, pei, pspCaller);
145 if(SUCCEEDED(hr) && byref_args)
147 for(arg = 0; arg < pdp->cArgs; arg++)
149 if(vt_list[arg] != V_VT(pdp->rgvarg + arg))
151 hr = DISP_E_BADCALLEE;
152 break;
157 if(hr == DISP_E_EXCEPTION)
159 if(pei && pei->pfnDeferredFillIn)
161 pei->pfnDeferredFillIn(pei);
162 pei->pfnDeferredFillIn = NULL;
166 for(arg = 0; arg < byref_args; arg++)
167 VariantInit(pdp->rgvarg + ref_idx[arg]);
169 HeapFree(GetProcessHeap(), 0, vt_list);
170 return hr;