/* * Misc marshaling routines * * 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 #include #define COBJMACROS #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, dummy_idx; VARIANT dummy_arg, *ref_arg = &dummy_arg, *copy_arg, *orig_arg = NULL; UINT *ref_idx = &dummy_idx; 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; }