dispex: Implement proxy and stub for IDispatchEx_InvokeEx.
This commit is contained in:
parent
2efd2355f7
commit
df07561ce2
|
@ -14396,6 +14396,10 @@ wine_fn_config_dll dispex
|
||||||
wine_fn_config_makefile dlls/dispex "dlls/Makedll.rules \$(MAKEDEP)"
|
wine_fn_config_makefile dlls/dispex "dlls/Makedll.rules \$(MAKEDEP)"
|
||||||
test "x$enable_dispex" != xno && wine_fn_append_file ALL_DLL_DIRS "dlls/dispex"
|
test "x$enable_dispex" != xno && wine_fn_append_file ALL_DLL_DIRS "dlls/dispex"
|
||||||
|
|
||||||
|
wine_fn_config_test dlls/dispex/tests dispex_test
|
||||||
|
wine_fn_config_makefile dlls/dispex/tests "Maketest.rules \$(MAKEDEP)"
|
||||||
|
test "x$enable_tests" != xno && wine_fn_append_file ALL_TEST_DIRS "dlls/dispex/tests"
|
||||||
|
|
||||||
wine_fn_config_dll display.drv16
|
wine_fn_config_dll display.drv16
|
||||||
wine_fn_config_makefile dlls/display.drv16 "dlls/Makedll.rules \$(MAKEDEP)"
|
wine_fn_config_makefile dlls/display.drv16 "dlls/Makedll.rules \$(MAKEDEP)"
|
||||||
test "x$enable_win16" != xno && wine_fn_append_file ALL_DLL_DIRS "dlls/display.drv16"
|
test "x$enable_win16" != xno && wine_fn_append_file ALL_DLL_DIRS "dlls/display.drv16"
|
||||||
|
@ -17080,6 +17084,7 @@ do
|
||||||
"dlls/dinput8/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dinput8/Makefile" ;;
|
"dlls/dinput8/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dinput8/Makefile" ;;
|
||||||
"dlls/dispdib.dll16/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dispdib.dll16/Makefile" ;;
|
"dlls/dispdib.dll16/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dispdib.dll16/Makefile" ;;
|
||||||
"dlls/dispex/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dispex/Makefile" ;;
|
"dlls/dispex/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dispex/Makefile" ;;
|
||||||
|
"dlls/dispex/tests/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dispex/tests/Makefile" ;;
|
||||||
"dlls/display.drv16/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/display.drv16/Makefile" ;;
|
"dlls/display.drv16/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/display.drv16/Makefile" ;;
|
||||||
"dlls/dmband/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dmband/Makefile" ;;
|
"dlls/dmband/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dmband/Makefile" ;;
|
||||||
"dlls/dmcompos/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dmcompos/Makefile" ;;
|
"dlls/dmcompos/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/dmcompos/Makefile" ;;
|
||||||
|
|
|
@ -2260,6 +2260,7 @@ WINE_CONFIG_TEST(dlls/dinput/tests)
|
||||||
WINE_CONFIG_DLL(dinput8,,[dinput8])
|
WINE_CONFIG_DLL(dinput8,,[dinput8])
|
||||||
WINE_CONFIG_DLL(dispdib.dll16,enable_win16)
|
WINE_CONFIG_DLL(dispdib.dll16,enable_win16)
|
||||||
WINE_CONFIG_DLL(dispex)
|
WINE_CONFIG_DLL(dispex)
|
||||||
|
WINE_CONFIG_TEST(dlls/dispex/tests)
|
||||||
WINE_CONFIG_DLL(display.drv16,enable_win16)
|
WINE_CONFIG_DLL(display.drv16,enable_win16)
|
||||||
WINE_CONFIG_DLL(dmband)
|
WINE_CONFIG_DLL(dmband)
|
||||||
WINE_CONFIG_DLL(dmcompos)
|
WINE_CONFIG_DLL(dmcompos)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
TOPSRCDIR = @top_srcdir@
|
||||||
|
TOPOBJDIR = ../../..
|
||||||
|
SRCDIR = @srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
TESTDLL = dispex.dll
|
||||||
|
IMPORTS = oleaut32 ole32 rpcrt4 user32 gdi32 advapi32 kernel32
|
||||||
|
|
||||||
|
C_SRCS = \
|
||||||
|
marshal.c
|
||||||
|
|
||||||
|
@MAKE_TEST_RULES@
|
|
@ -0,0 +1,416 @@
|
||||||
|
/*
|
||||||
|
* Tests for marshaling IDispatchEx
|
||||||
|
*
|
||||||
|
* Copyright 2005-2006 Robert Shearman
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
#define CONST_VTABLE
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "initguid.h"
|
||||||
|
#include "objidl.h"
|
||||||
|
#include "dispex.h"
|
||||||
|
|
||||||
|
#include "wine/test.h"
|
||||||
|
|
||||||
|
#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", (unsigned long int)hr)
|
||||||
|
|
||||||
|
#define RELEASEMARSHALDATA WM_USER
|
||||||
|
|
||||||
|
struct host_object_data
|
||||||
|
{
|
||||||
|
IStream *stream;
|
||||||
|
IID iid;
|
||||||
|
IUnknown *object;
|
||||||
|
MSHLFLAGS marshal_flags;
|
||||||
|
HANDLE marshal_event;
|
||||||
|
HANDLE error_event;
|
||||||
|
IMessageFilter *filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DWORD CALLBACK host_object_proc(LPVOID p)
|
||||||
|
{
|
||||||
|
struct host_object_data *data = p;
|
||||||
|
HRESULT hr;
|
||||||
|
MSG msg;
|
||||||
|
|
||||||
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
|
|
||||||
|
if (data->filter)
|
||||||
|
{
|
||||||
|
IMessageFilter * prev_filter = NULL;
|
||||||
|
hr = CoRegisterMessageFilter(data->filter, &prev_filter);
|
||||||
|
if (prev_filter) IMessageFilter_Release(prev_filter);
|
||||||
|
ok_ole_success(hr, CoRegisterMessageFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
|
||||||
|
|
||||||
|
/* force the message queue to be created before signaling parent thread */
|
||||||
|
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
||||||
|
|
||||||
|
if(hr == S_OK)
|
||||||
|
SetEvent(data->marshal_event);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
win_skip("IDispatchEx marshaller not available.\n");
|
||||||
|
SetEvent(data->error_event);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (GetMessage(&msg, NULL, 0, 0))
|
||||||
|
{
|
||||||
|
if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
|
||||||
|
{
|
||||||
|
trace("releasing marshal data\n");
|
||||||
|
CoReleaseMarshalData(data->stream);
|
||||||
|
SetEvent((HANDLE)msg.lParam);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, data);
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
|
||||||
|
{
|
||||||
|
DWORD tid = 0, ret;
|
||||||
|
HANDLE events[2];
|
||||||
|
struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
|
||||||
|
|
||||||
|
data->stream = stream;
|
||||||
|
data->iid = *riid;
|
||||||
|
data->object = object;
|
||||||
|
data->marshal_flags = marshal_flags;
|
||||||
|
data->marshal_event = events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
data->error_event = events[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
data->filter = filter;
|
||||||
|
|
||||||
|
*thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
|
||||||
|
|
||||||
|
/* wait for marshaling to complete before returning */
|
||||||
|
ret = WaitForMultipleObjects(2, events, FALSE, INFINITE);
|
||||||
|
CloseHandle(events[0]);
|
||||||
|
CloseHandle(events[1]);
|
||||||
|
|
||||||
|
if(ret == WAIT_OBJECT_0) return tid;
|
||||||
|
|
||||||
|
WaitForSingleObject(*thread, INFINITE);
|
||||||
|
CloseHandle(*thread);
|
||||||
|
*thread = INVALID_HANDLE_VALUE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
|
||||||
|
{
|
||||||
|
return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_host_object(DWORD tid, HANDLE thread)
|
||||||
|
{
|
||||||
|
BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
|
||||||
|
ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
|
||||||
|
/* be careful of races - don't return until hosting thread has terminated */
|
||||||
|
WaitForSingleObject(thread, INFINITE);
|
||||||
|
CloseHandle(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const IDispatchExVtbl *lpVtbl;
|
||||||
|
LONG refs;
|
||||||
|
} dispex;
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_QueryInterface(IDispatchEx* iface,
|
||||||
|
REFIID iid, void **obj)
|
||||||
|
{
|
||||||
|
trace("QI {%08x-...}\n", iid->Data1);
|
||||||
|
if(IsEqualIID(iid, &IID_IUnknown) ||
|
||||||
|
IsEqualIID(iid, &IID_IDispatchEx))
|
||||||
|
{
|
||||||
|
IDispatchEx_AddRef(iface);
|
||||||
|
*obj = iface;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*obj = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI dispex_AddRef(IDispatchEx* iface)
|
||||||
|
{
|
||||||
|
dispex *This = (dispex *)iface;
|
||||||
|
trace("AddRef\n");
|
||||||
|
|
||||||
|
return InterlockedIncrement(&This->refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG WINAPI dispex_Release(IDispatchEx* iface)
|
||||||
|
{
|
||||||
|
dispex *This = (dispex *)iface;
|
||||||
|
ULONG refs = InterlockedDecrement(&This->refs);
|
||||||
|
trace("Release\n");
|
||||||
|
if(!refs)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, This);
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetTypeInfoCount(IDispatchEx* iface,
|
||||||
|
UINT *pctinfo)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetTypeInfo(IDispatchEx* iface,
|
||||||
|
UINT iTInfo,
|
||||||
|
LCID lcid,
|
||||||
|
ITypeInfo **ppTInfo)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetIDsOfNames(IDispatchEx* iface,
|
||||||
|
REFIID riid,
|
||||||
|
LPOLESTR *rgszNames,
|
||||||
|
UINT cNames,
|
||||||
|
LCID lcid,
|
||||||
|
DISPID *rgDispId)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_Invoke(IDispatchEx* iface,
|
||||||
|
DISPID dispIdMember,
|
||||||
|
REFIID riid,
|
||||||
|
LCID lcid,
|
||||||
|
WORD wFlags,
|
||||||
|
DISPPARAMS *pDispParams,
|
||||||
|
VARIANT *pVarResult,
|
||||||
|
EXCEPINFO *pExcepInfo,
|
||||||
|
UINT *puArgErr)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetDispID(IDispatchEx* iface,
|
||||||
|
BSTR bstrName,
|
||||||
|
DWORD grfdex,
|
||||||
|
DISPID *pid)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_InvokeEx(IDispatchEx* iface,
|
||||||
|
DISPID id,
|
||||||
|
LCID lcid,
|
||||||
|
WORD wFlags,
|
||||||
|
DISPPARAMS *pdp,
|
||||||
|
VARIANT *pvarRes,
|
||||||
|
EXCEPINFO *pei,
|
||||||
|
IServiceProvider *pspCaller)
|
||||||
|
{
|
||||||
|
if(id == 1)
|
||||||
|
{
|
||||||
|
ok(pdp->cArgs == 0, "got %d\n", pdp->cArgs);
|
||||||
|
todo_wine
|
||||||
|
ok(pei == NULL, "got non-NULL excepinfo\n");
|
||||||
|
todo_wine
|
||||||
|
ok(pvarRes == NULL, "got non-NULL result\n");
|
||||||
|
}
|
||||||
|
else if(id == 2)
|
||||||
|
{
|
||||||
|
ok(pdp->cArgs == 2, "got %d\n", pdp->cArgs);
|
||||||
|
ok(V_VT(&pdp->rgvarg[0]) == VT_INT, "got %04x\n", V_VT(&pdp->rgvarg[0]));
|
||||||
|
ok(V_VT(&pdp->rgvarg[1]) == (VT_INT | VT_BYREF), "got %04x\n", V_VT(&pdp->rgvarg[1]));
|
||||||
|
ok(*V_INTREF(&pdp->rgvarg[1]) == 0xbeef, "got %08x\n", *V_INTREF(&pdp->rgvarg[1]));
|
||||||
|
*V_INTREF(&pdp->rgvarg[1]) = 0xdead;
|
||||||
|
}
|
||||||
|
else if(id == 3)
|
||||||
|
{
|
||||||
|
ok(pdp->cArgs == 2, "got %d\n", pdp->cArgs);
|
||||||
|
ok(V_VT(&pdp->rgvarg[0]) == VT_INT, "got %04x\n", V_VT(&pdp->rgvarg[0]));
|
||||||
|
ok(V_VT(&pdp->rgvarg[1]) == (VT_INT | VT_BYREF), "got %04x\n", V_VT(&pdp->rgvarg[1]));
|
||||||
|
V_VT(&pdp->rgvarg[0]) = VT_I4;
|
||||||
|
}
|
||||||
|
else if(id == 4)
|
||||||
|
{
|
||||||
|
todo_wine
|
||||||
|
ok(wFlags == 0xf, "got %04x\n", wFlags);
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_DeleteMemberByName(IDispatchEx* iface,
|
||||||
|
BSTR bstrName,
|
||||||
|
DWORD grfdex)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_DeleteMemberByDispID(IDispatchEx* iface, DISPID id)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetMemberProperties(IDispatchEx* iface, DISPID id,
|
||||||
|
DWORD grfdexFetch, DWORD *pgrfdex)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetMemberName(IDispatchEx* iface,
|
||||||
|
DISPID id, BSTR *pbstrName)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetNextDispID(IDispatchEx* iface,
|
||||||
|
DWORD grfdex,
|
||||||
|
DISPID id,
|
||||||
|
DISPID *pid)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI dispex_GetNameSpaceParent(IDispatchEx* iface,
|
||||||
|
IUnknown **ppunk)
|
||||||
|
{
|
||||||
|
trace("\n");
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const IDispatchExVtbl dispex_vtable =
|
||||||
|
{
|
||||||
|
dispex_QueryInterface,
|
||||||
|
dispex_AddRef,
|
||||||
|
dispex_Release,
|
||||||
|
dispex_GetTypeInfoCount,
|
||||||
|
dispex_GetTypeInfo,
|
||||||
|
dispex_GetIDsOfNames,
|
||||||
|
dispex_Invoke,
|
||||||
|
dispex_GetDispID,
|
||||||
|
dispex_InvokeEx,
|
||||||
|
dispex_DeleteMemberByName,
|
||||||
|
dispex_DeleteMemberByDispID,
|
||||||
|
dispex_GetMemberProperties,
|
||||||
|
dispex_GetMemberName,
|
||||||
|
dispex_GetNextDispID,
|
||||||
|
dispex_GetNameSpaceParent
|
||||||
|
};
|
||||||
|
|
||||||
|
static IDispatchEx *dispex_create(void)
|
||||||
|
{
|
||||||
|
dispex *This;
|
||||||
|
|
||||||
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
||||||
|
if (!This) return NULL;
|
||||||
|
This->lpVtbl = &dispex_vtable;
|
||||||
|
This->refs = 1;
|
||||||
|
return (IDispatchEx *)This;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_dispex(void)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IStream *stream;
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE thread;
|
||||||
|
static const LARGE_INTEGER zero;
|
||||||
|
IDispatchEx *dispex = dispex_create();
|
||||||
|
DISPPARAMS params;
|
||||||
|
VARIANTARG args[10];
|
||||||
|
INT i;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
|
||||||
|
ok(hr == S_OK, "got %08x\n", hr);
|
||||||
|
tid = start_host_object(stream, &IID_IDispatchEx, (IUnknown *)dispex, MSHLFLAGS_NORMAL, &thread);
|
||||||
|
IDispatchEx_Release(dispex);
|
||||||
|
if(tid == 0)
|
||||||
|
{
|
||||||
|
IStream_Release(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
|
||||||
|
hr = CoUnmarshalInterface(stream, &IID_IDispatchEx, (void **)&dispex);
|
||||||
|
ok(hr == S_OK, "got %08x\n", hr);
|
||||||
|
IStream_Release(stream);
|
||||||
|
|
||||||
|
params.rgvarg = NULL;
|
||||||
|
params.rgdispidNamedArgs = NULL;
|
||||||
|
params.cArgs = 0;
|
||||||
|
params.cNamedArgs = 0;
|
||||||
|
hr = IDispatchEx_InvokeEx(dispex, 1, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);
|
||||||
|
ok(hr == S_OK, "got %08x\n", hr);
|
||||||
|
|
||||||
|
params.rgvarg = args;
|
||||||
|
params.rgdispidNamedArgs = NULL;
|
||||||
|
params.cArgs = 2;
|
||||||
|
params.cNamedArgs = 0;
|
||||||
|
V_VT(&args[0]) = VT_INT;
|
||||||
|
V_INT(&args[0]) = 0xcafe;
|
||||||
|
V_VT(&args[1]) = VT_INT | VT_BYREF;
|
||||||
|
V_INTREF(&args[1]) = &i;
|
||||||
|
i = 0xbeef;
|
||||||
|
hr = IDispatchEx_InvokeEx(dispex, 2, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);
|
||||||
|
ok(hr == S_OK, "got %08x\n", hr);
|
||||||
|
ok(i == 0xdead, "got %08x\n", i);
|
||||||
|
|
||||||
|
/* change one of the argument vts */
|
||||||
|
i = 0xbeef;
|
||||||
|
hr = IDispatchEx_InvokeEx(dispex, 3, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);
|
||||||
|
todo_wine
|
||||||
|
ok(hr == DISP_E_BADCALLEE, "got %08x\n", hr);
|
||||||
|
|
||||||
|
hr = IDispatchEx_InvokeEx(dispex, 4, LOCALE_SYSTEM_DEFAULT, 0xffff, ¶ms, NULL, NULL, NULL);
|
||||||
|
ok(hr == S_OK, "got %08x\n", hr);
|
||||||
|
|
||||||
|
IDispatchEx_Release(dispex);
|
||||||
|
end_host_object(tid, thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(marshal)
|
||||||
|
{
|
||||||
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
|
|
||||||
|
test_dispex();
|
||||||
|
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
|
@ -41,18 +41,92 @@ HRESULT CALLBACK IDispatchEx_InvokeEx_Proxy(IDispatchEx* This, DISPID id, LCID l
|
||||||
DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei,
|
DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei,
|
||||||
IServiceProvider *pspCaller)
|
IServiceProvider *pspCaller)
|
||||||
{
|
{
|
||||||
FIXME("(%p)->(%08x, %04x, %04x, %p, %p, %p, %p): stub\n", This, id, lcid, wFlags,
|
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;
|
||||||
|
|
||||||
|
TRACE("(%p)->(%08x, %04x, %04x, %p, %p, %p, %p)\n", This, id, lcid, wFlags,
|
||||||
pdp, pvarRes, pei, pspCaller);
|
pdp, pvarRes, pei, pspCaller);
|
||||||
return E_NOTIMPL;
|
|
||||||
|
if(!pvarRes) pvarRes = &result;
|
||||||
|
if(!pei) pei = &excep_info;
|
||||||
|
|
||||||
|
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, wFlags, pdp, pvarRes, pei, pspCaller,
|
||||||
|
byref_args, ref_idx, ref_arg);
|
||||||
|
|
||||||
|
if(byref_args)
|
||||||
|
{
|
||||||
|
CoTaskMemFree(pdp->rgvarg);
|
||||||
|
pdp->rgvarg = orig_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pvarRes == &result) VariantClear(pvarRes);
|
||||||
|
if(pei == &excep_info)
|
||||||
|
{
|
||||||
|
SysFreeString(pei->bstrSource);
|
||||||
|
SysFreeString(pei->bstrDescription);
|
||||||
|
SysFreeString(pei->bstrHelpFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT __RPC_STUB IDispatchEx_InvokeEx_Stub(IDispatchEx* This, DISPID id, LCID lcid, DWORD dwFlags,
|
HRESULT __RPC_STUB IDispatchEx_InvokeEx_Stub(IDispatchEx* This, DISPID id, LCID lcid, DWORD dwFlags,
|
||||||
DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei,
|
DISPPARAMS *pdp, VARIANT *result, EXCEPINFO *pei,
|
||||||
IServiceProvider *pspCaller, UINT cvarRefArg,
|
IServiceProvider *pspCaller, UINT byref_args,
|
||||||
UINT *rgiRefArg, VARIANT *rgvarRefArg)
|
UINT *ref_idx, VARIANT *ref_arg)
|
||||||
{
|
{
|
||||||
FIXME("(%p)->(%08x, %04x, %08x, %p, %p, %p, %p, %d, %p, %p): stub\n", This, id, lcid, dwFlags,
|
HRESULT hr;
|
||||||
pdp, pvarRes, pei, pspCaller, cvarRefArg, rgiRefArg, rgvarRefArg);
|
UINT arg;
|
||||||
return E_NOTIMPL;
|
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
hr = IDispatchEx_InvokeEx(This, id, lcid, dwFlags, pdp, result, pei, pspCaller);
|
||||||
|
|
||||||
|
for(arg = 0; arg < byref_args; arg++)
|
||||||
|
VariantInit(pdp->rgvarg + ref_idx[arg]);
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue