mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 11:43:31 +00:00
173 lines
5.1 KiB
C
173 lines
5.1 KiB
C
/*
|
|
* 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 <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, 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;
|
|
}
|