|  | /* | 
|  | *    Misc marshaling routinues | 
|  | * | 
|  | * Copyright 2010 Huw Davies | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  | #include <stdarg.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winerror.h" | 
|  | #include "objbase.h" | 
|  | #include "oleauto.h" | 
|  | #include "dispex.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(ole); | 
|  |  | 
|  | #define NULL_RESULT    0x20000 | 
|  | #define NULL_EXCEPINFO 0x40000 | 
|  |  | 
|  | HRESULT CALLBACK IDispatchEx_InvokeEx_Proxy(IDispatchEx* This, DISPID id, LCID lcid, WORD wFlags, | 
|  | DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, | 
|  | IServiceProvider *pspCaller) | 
|  | { | 
|  | HRESULT hr; | 
|  | VARIANT result; | 
|  | EXCEPINFO excep_info; | 
|  | UINT byref_args, arg; | 
|  | VARIANT dummy_arg, *ref_arg = &dummy_arg, *copy_arg, *orig_arg = NULL; | 
|  | UINT *ref_idx = NULL; | 
|  | DWORD dword_flags = wFlags & 0xf; | 
|  |  | 
|  | TRACE("(%p)->(%08x, %04x, %04x, %p, %p, %p, %p)\n", This, id, lcid, wFlags, | 
|  | pdp, pvarRes, pei, pspCaller); | 
|  |  | 
|  | if(!pvarRes) | 
|  | { | 
|  | pvarRes = &result; | 
|  | dword_flags |= NULL_RESULT; | 
|  | } | 
|  |  | 
|  | if(!pei) | 
|  | { | 
|  | pei = &excep_info; | 
|  | dword_flags |= NULL_EXCEPINFO; | 
|  | } | 
|  |  | 
|  | for(arg = 0, byref_args = 0; arg < pdp->cArgs; arg++) | 
|  | if(V_ISBYREF(pdp->rgvarg + arg)) byref_args++; | 
|  |  | 
|  | if(byref_args) | 
|  | { | 
|  | DWORD size = pdp->cArgs * sizeof(VARIANT) + | 
|  | byref_args * (sizeof(VARIANT) + sizeof(UINT)); | 
|  |  | 
|  | copy_arg = CoTaskMemAlloc(size); | 
|  | if(!copy_arg) return E_OUTOFMEMORY; | 
|  |  | 
|  | ref_arg = copy_arg + pdp->cArgs; | 
|  | ref_idx = (UINT*)(ref_arg + byref_args); | 
|  |  | 
|  | /* copy the byref args to ref_arg[], the others go to copy_arg[] */ | 
|  | for(arg = 0, byref_args = 0; arg < pdp->cArgs; arg++) | 
|  | { | 
|  | if(V_ISBYREF(pdp->rgvarg + arg)) | 
|  | { | 
|  | ref_arg[byref_args] = pdp->rgvarg[arg]; | 
|  | ref_idx[byref_args] = arg; | 
|  | VariantInit(copy_arg + arg); | 
|  | byref_args++; | 
|  | } | 
|  | else | 
|  | copy_arg[arg] = pdp->rgvarg[arg]; | 
|  | } | 
|  |  | 
|  | orig_arg = pdp->rgvarg; | 
|  | pdp->rgvarg = copy_arg; | 
|  | } | 
|  |  | 
|  | hr = IDispatchEx_RemoteInvokeEx_Proxy(This, id, lcid, dword_flags, pdp, pvarRes, pei, pspCaller, | 
|  | byref_args, ref_idx, ref_arg); | 
|  |  | 
|  | if(byref_args) | 
|  | { | 
|  | CoTaskMemFree(pdp->rgvarg); | 
|  | pdp->rgvarg = orig_arg; | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | HRESULT __RPC_STUB IDispatchEx_InvokeEx_Stub(IDispatchEx* This, DISPID id, LCID lcid, DWORD dwFlags, | 
|  | DISPPARAMS *pdp, VARIANT *result, EXCEPINFO *pei, | 
|  | IServiceProvider *pspCaller, UINT byref_args, | 
|  | UINT *ref_idx, VARIANT *ref_arg) | 
|  | { | 
|  | HRESULT hr; | 
|  | UINT arg; | 
|  | VARTYPE *vt_list = NULL; | 
|  |  | 
|  | TRACE("(%p)->(%08x, %04x, %08x, %p, %p, %p, %p, %d, %p, %p)\n", This, id, lcid, dwFlags, | 
|  | pdp, result, pei, pspCaller, byref_args, ref_idx, ref_arg); | 
|  |  | 
|  | VariantInit(result); | 
|  | memset(pei, 0, sizeof(*pei)); | 
|  |  | 
|  | for(arg = 0; arg < byref_args; arg++) | 
|  | pdp->rgvarg[ref_idx[arg]] = ref_arg[arg]; | 
|  |  | 
|  | if(dwFlags & NULL_RESULT) result = NULL; | 
|  | if(dwFlags & NULL_EXCEPINFO) pei = NULL; | 
|  |  | 
|  | /* Create an array of the original VTs to check that the function doesn't change | 
|  | any on return. */ | 
|  | if(byref_args) | 
|  | { | 
|  | vt_list = HeapAlloc(GetProcessHeap(), 0, pdp->cArgs * sizeof(vt_list[0])); | 
|  | if(!vt_list) return E_OUTOFMEMORY; | 
|  | for(arg = 0; arg < pdp->cArgs; arg++) | 
|  | vt_list[arg] = V_VT(pdp->rgvarg + arg); | 
|  | } | 
|  |  | 
|  | hr = IDispatchEx_InvokeEx(This, id, lcid, dwFlags & 0xffff, pdp, result, pei, pspCaller); | 
|  |  | 
|  | if(SUCCEEDED(hr) && byref_args) | 
|  | { | 
|  | for(arg = 0; arg < pdp->cArgs; arg++) | 
|  | { | 
|  | if(vt_list[arg] != V_VT(pdp->rgvarg + arg)) | 
|  | { | 
|  | hr = DISP_E_BADCALLEE; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if(hr == DISP_E_EXCEPTION) | 
|  | { | 
|  | if(pei && pei->pfnDeferredFillIn) | 
|  | { | 
|  | pei->pfnDeferredFillIn(pei); | 
|  | pei->pfnDeferredFillIn = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | for(arg = 0; arg < byref_args; arg++) | 
|  | VariantInit(pdp->rgvarg + ref_idx[arg]); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, vt_list); | 
|  | return hr; | 
|  | } |