oleaut32/tests: Add some tests for marshalling interfaces.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2018-10-29 23:20:23 -05:00 committed by Alexandre Julliard
parent 96b0bdc38c
commit 09076372eb
2 changed files with 441 additions and 0 deletions

View File

@ -34,6 +34,12 @@ static HRESULT (WINAPI *pVarAdd)(LPVARIANT,LPVARIANT,LPVARIANT);
#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
static inline void release_iface_(unsigned int line, void *iface)
{
ULONG ref = IUnknown_Release((IUnknown *)iface);
ok_(__FILE__, line)(!ref, "Got outstanding refcount %d.\n", ref);
}
#define release_iface(a) release_iface_(__LINE__, a)
/* ULL suffix is not portable */
#define ULL_CONST(dw1, dw2) ((((ULONGLONG)dw1) << 32) | (ULONGLONG)dw2)
@ -370,6 +376,98 @@ static ItestDualVtbl TestDualVtbl = {
static ItestDual TestDual = { &TestDualVtbl };
static ItestDual TestDualDisp = { &TestDualVtbl };
struct disp_obj
{
ISomethingFromDispatch ISomethingFromDispatch_iface;
LONG ref;
};
static inline struct disp_obj *impl_from_ISomethingFromDispatch(ISomethingFromDispatch *iface)
{
return CONTAINING_RECORD(iface, struct disp_obj, ISomethingFromDispatch_iface);
}
static HRESULT WINAPI disp_obj_QueryInterface(ISomethingFromDispatch *iface, REFIID iid, void **out)
{
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IDispatch)
|| IsEqualGUID(iid, &IID_ISomethingFromDispatch))
{
*out = iface;
ISomethingFromDispatch_AddRef(iface);
return S_OK;
}
*out = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI disp_obj_AddRef(ISomethingFromDispatch *iface)
{
struct disp_obj *obj = impl_from_ISomethingFromDispatch(iface);
return ++obj->ref;
}
static ULONG WINAPI disp_obj_Release(ISomethingFromDispatch *iface)
{
struct disp_obj *obj = impl_from_ISomethingFromDispatch(iface);
LONG ref = --obj->ref;
if (!ref)
CoTaskMemFree(obj);
return ref;
}
static HRESULT WINAPI disp_obj_GetTypeInfoCount(ISomethingFromDispatch *iface, UINT *count)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI disp_obj_GetTypeInfo(ISomethingFromDispatch *iface,
UINT index, LCID lcid, ITypeInfo **typeinfo)
{
ok(index == 0xdeadbeef, "Got unexpected index %#x.\n", index);
return 0xbeefdead;
}
static HRESULT WINAPI disp_obj_GetIDsOfNames(ISomethingFromDispatch *iface,
REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *ids)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI disp_obj_Invoke(ISomethingFromDispatch *iface, DISPID id, REFIID iid, LCID lcid,
WORD flags, DISPPARAMS *dispparams, VARIANT *result, EXCEPINFO *excepinfo, UINT *errarg)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI disp_obj_anotherfn(ISomethingFromDispatch *iface)
{
return 0x01234567;
}
static const ISomethingFromDispatchVtbl disp_obj_vtbl =
{
disp_obj_QueryInterface,
disp_obj_AddRef,
disp_obj_Release,
disp_obj_GetTypeInfoCount,
disp_obj_GetTypeInfo,
disp_obj_GetIDsOfNames,
disp_obj_Invoke,
disp_obj_anotherfn,
};
static ISomethingFromDispatch *create_disp_obj(void)
{
struct disp_obj *obj = CoTaskMemAlloc(sizeof(*obj));
obj->ISomethingFromDispatch_iface.lpVtbl = &disp_obj_vtbl;
obj->ref = 1;
return &obj->ISomethingFromDispatch_iface;
}
static int testmode;
typedef struct Widget
@ -1011,6 +1109,90 @@ todo_wine_if(testmode == 2)
return S_OK;
}
/* Call methods to check that we have valid proxies to each interface. */
static void check_iface_marshal(IUnknown *unk, IDispatch *disp, ISomethingFromDispatch *sfd)
{
ISomethingFromDispatch *sfd2;
ITypeInfo *typeinfo;
HRESULT hr;
hr = IUnknown_QueryInterface(unk, &IID_ISomethingFromDispatch, (void **)&sfd2);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ISomethingFromDispatch_Release(sfd2);
hr = IDispatch_GetTypeInfo(disp, 0xdeadbeef, 0, &typeinfo);
ok(hr == 0xbeefdead, "Got hr %#x.\n", hr);
hr = ISomethingFromDispatch_anotherfn(sfd);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
}
static HRESULT WINAPI Widget_iface_in(IWidget *iface, IUnknown *unk, IDispatch *disp, ISomethingFromDispatch *sfd)
{
if (testmode == 0)
check_iface_marshal(unk, disp, sfd);
else if (testmode == 1)
{
ok(!unk, "Got iface %p.\n", unk);
ok(!disp, "Got iface %p.\n", disp);
ok(!sfd, "Got iface %p.\n", sfd);
}
return S_OK;
}
static HRESULT WINAPI Widget_iface_out(IWidget *iface, IUnknown **unk, IDispatch **disp, ISomethingFromDispatch **sfd)
{
todo_wine
ok(!*unk, "Got iface %p.\n", *unk);
ok(!*disp, "Got iface %p.\n", *disp);
ok(!*sfd, "Got iface %p.\n", *sfd);
if (testmode == 0)
{
*unk = (IUnknown *)create_disp_obj();
*disp = (IDispatch *)create_disp_obj();
*sfd = create_disp_obj();
}
return S_OK;
}
static HRESULT WINAPI Widget_iface_ptr(IWidget *iface, ISomethingFromDispatch **in,
ISomethingFromDispatch **out, ISomethingFromDispatch **in_out)
{
HRESULT hr;
ok(!*out, "Got [out] %p.\n", *out);
if (testmode == 0 || testmode == 1)
{
hr = ISomethingFromDispatch_anotherfn(*in);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
hr = ISomethingFromDispatch_anotherfn(*in_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
}
if (testmode == 1)
{
*out = create_disp_obj();
ISomethingFromDispatch_Release(*in_out);
*in_out = create_disp_obj();
}
else if (testmode == 2)
{
ok(!*in, "Got [in] %p.\n", *in);
ok(!*in_out, "Got [in, out] %p.\n", *in_out);
*in_out = create_disp_obj();
}
else if (testmode == 3)
{
hr = ISomethingFromDispatch_anotherfn(*in_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
ISomethingFromDispatch_Release(*in_out);
*in_out = NULL;
}
return S_OK;
}
static const struct IWidgetVtbl Widget_VTable =
{
Widget_QueryInterface,
@ -1056,6 +1238,9 @@ static const struct IWidgetVtbl Widget_VTable =
Widget_basetypes_out,
Widget_int_ptr,
Widget_int_ptr_ptr,
Widget_iface_in,
Widget_iface_out,
Widget_iface_ptr,
};
static HRESULT WINAPI StaticWidget_QueryInterface(IStaticWidget *iface, REFIID riid, void **ppvObject)
@ -1573,6 +1758,248 @@ if (0) {
}
}
static void test_marshal_iface(IWidget *widget, IDispatch *disp)
{
VARIANTARG arg[3];
DISPPARAMS dispparams = {arg, NULL, ARRAY_SIZE(arg), 0};
ISomethingFromDispatch *sfd1, *sfd2, *sfd3, *proxy_sfd, *sfd_in, *sfd_out, *sfd_in_out;
IUnknown *proxy_unk, *proxy_unk2, *unk_in, *unk_out, *unk_in_out;
IDispatch *proxy_disp;
HRESULT hr;
testmode = 0;
sfd1 = create_disp_obj();
sfd2 = create_disp_obj();
sfd3 = create_disp_obj();
hr = IWidget_iface_in(widget, (IUnknown *)create_disp_obj(),
(IDispatch *)create_disp_obj(), create_disp_obj());
ok(hr == S_OK, "Got hr %#x.\n", hr);
release_iface(sfd1);
release_iface(sfd2);
release_iface(sfd3);
testmode = 1;
hr = IWidget_iface_in(widget, NULL, NULL, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
testmode = 0;
proxy_unk = (IUnknown *)0xdeadbeef;
proxy_disp = (IDispatch *)0xdeadbeef;
proxy_sfd = (ISomethingFromDispatch *)0xdeadbeef;
hr = IWidget_iface_out(widget, &proxy_unk, &proxy_disp, &proxy_sfd);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_iface_marshal(proxy_unk, proxy_disp, proxy_sfd);
release_iface(proxy_unk);
release_iface(proxy_disp);
release_iface(proxy_sfd);
if (0) {
testmode = 1;
hr = IWidget_iface_out(widget, &proxy_unk, &proxy_disp, &proxy_sfd);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!proxy_unk, "Got unexpected proxy %p.\n", proxy_unk);
ok(!proxy_disp, "Got unexpected proxy %p.\n", proxy_disp);
ok(!proxy_sfd, "Got unexpected proxy %p.\n", proxy_sfd);
}
testmode = 0;
sfd_in = sfd1 = create_disp_obj();
sfd_out = sfd2 = create_disp_obj();
sfd_in_out = sfd3 = create_disp_obj();
hr = IWidget_iface_ptr(widget, &sfd_in, &sfd_out, &sfd_in_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(sfd_in == sfd1, "[in] parameter should not have changed.\n");
ok(!sfd_out, "[out] parameter should have been cleared.\n");
ok(sfd_in_out == sfd3, "[in, out] parameter should not have changed.\n");
release_iface(sfd1);
release_iface(sfd2);
todo_wine
release_iface(sfd3);
testmode = 1;
sfd_in = sfd1 = create_disp_obj();
sfd_in_out = sfd3 = create_disp_obj();
ISomethingFromDispatch_AddRef(sfd_in_out);
hr = IWidget_iface_ptr(widget, &sfd_in, &sfd_out, &sfd_in_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = ISomethingFromDispatch_anotherfn(sfd_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
ok(sfd_in_out != sfd3, "[in, out] parameter should have changed.\n");
hr = ISomethingFromDispatch_anotherfn(sfd_in_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
release_iface(sfd_out);
release_iface(sfd_in_out);
release_iface(sfd1);
todo_wine
release_iface(sfd3);
testmode = 2;
sfd_in = sfd_out = sfd_in_out = NULL;
hr = IWidget_iface_ptr(widget, &sfd_in, &sfd_out, &sfd_in_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!sfd_out, "[out] parameter should not have been set.\n");
hr = ISomethingFromDispatch_anotherfn(sfd_in_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
release_iface(sfd_in_out);
testmode = 3;
sfd_in = sfd_out = NULL;
sfd_in_out = sfd3 = create_disp_obj();
ISomethingFromDispatch_AddRef(sfd_in_out);
hr = IWidget_iface_ptr(widget, &sfd_in, &sfd_out, &sfd_in_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!sfd_in_out, "Got [in, out] %p.\n", sfd_in_out);
todo_wine
release_iface(sfd3);
/* Test with Invoke(). Note that since we pass VT_UNKNOWN, we don't get our
* interface back, but rather an IUnknown. */
testmode = 0;
sfd1 = create_disp_obj();
sfd2 = create_disp_obj();
sfd3 = create_disp_obj();
V_VT(&arg[2]) = VT_UNKNOWN; V_UNKNOWN(&arg[2]) = (IUnknown *)sfd1;
V_VT(&arg[1]) = VT_UNKNOWN; V_UNKNOWN(&arg[1]) = (IUnknown *)sfd2;
V_VT(&arg[0]) = VT_UNKNOWN; V_UNKNOWN(&arg[0]) = (IUnknown *)sfd3;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_IN, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
V_VT(&arg[2]) = VT_DISPATCH; V_DISPATCH(&arg[2]) = (IDispatch *)sfd1;
V_VT(&arg[1]) = VT_DISPATCH; V_DISPATCH(&arg[1]) = (IDispatch *)sfd2;
V_VT(&arg[0]) = VT_DISPATCH; V_DISPATCH(&arg[0]) = (IDispatch *)sfd3;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_IN, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
release_iface(sfd1);
release_iface(sfd2);
release_iface(sfd3);
testmode = 1;
V_VT(&arg[2]) = VT_UNKNOWN; V_UNKNOWN(&arg[2]) = NULL;
V_VT(&arg[1]) = VT_UNKNOWN; V_UNKNOWN(&arg[1]) = NULL;
V_VT(&arg[0]) = VT_UNKNOWN; V_UNKNOWN(&arg[0]) = NULL;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_IN, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
testmode = 0;
proxy_unk = proxy_unk2 = NULL;
proxy_disp = NULL;
V_VT(&arg[2]) = VT_UNKNOWN|VT_BYREF; V_UNKNOWNREF(&arg[2]) = &proxy_unk;
V_VT(&arg[1]) = VT_DISPATCH|VT_BYREF; V_DISPATCHREF(&arg[1]) = &proxy_disp;
V_VT(&arg[0]) = VT_UNKNOWN|VT_BYREF; V_UNKNOWNREF(&arg[0]) = &proxy_unk2;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_OUT, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
if (hr == S_OK) {
hr = IUnknown_QueryInterface(proxy_unk2, &IID_ISomethingFromDispatch, (void **)&proxy_sfd);
ok(hr == S_OK, "Got hr %#x.\n", hr);
check_iface_marshal(proxy_unk, proxy_disp, proxy_sfd);
ISomethingFromDispatch_Release(proxy_sfd);
release_iface(proxy_unk);
release_iface(proxy_disp);
release_iface(proxy_unk2);
}
testmode = 1;
proxy_unk = proxy_unk2 = NULL;
proxy_disp = NULL;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_OUT, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!proxy_unk, "Got unexpected proxy %p.\n", proxy_unk);
ok(!proxy_disp, "Got unexpected proxy %p.\n", proxy_disp);
ok(!proxy_unk2, "Got unexpected proxy %p.\n", proxy_unk2);
testmode = 0;
sfd1 = create_disp_obj();
sfd3 = create_disp_obj();
unk_in = (IUnknown *)sfd1;
unk_out = NULL;
unk_in_out = (IUnknown *)sfd3;
V_VT(&arg[2]) = VT_UNKNOWN|VT_BYREF; V_UNKNOWNREF(&arg[2]) = &unk_in;
V_VT(&arg[1]) = VT_UNKNOWN|VT_BYREF; V_UNKNOWNREF(&arg[1]) = &unk_out;
V_VT(&arg[0]) = VT_UNKNOWN|VT_BYREF; V_UNKNOWNREF(&arg[0]) = &unk_in_out;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_PTR, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(unk_in == (IUnknown *)sfd1, "[in] parameter should not have changed.\n");
ok(!unk_out, "[out] parameter should have been cleared.\n");
ok(unk_in_out == (IUnknown *)sfd3, "[in, out] parameter should not have changed.\n");
release_iface(sfd1);
release_iface(sfd3);
testmode = 1;
sfd1 = create_disp_obj();
sfd3 = create_disp_obj();
unk_in = (IUnknown *)sfd1;
unk_out = NULL;
unk_in_out = (IUnknown *)sfd3;
IUnknown_AddRef(unk_in_out);
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_PTR, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
if (hr == S_OK) {
hr = IUnknown_QueryInterface(unk_out, &IID_ISomethingFromDispatch, (void **)&sfd_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = ISomethingFromDispatch_anotherfn(sfd_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
ISomethingFromDispatch_Release(sfd_out);
ok(unk_in_out != (IUnknown *)sfd3, "[in, out] parameter should have changed.\n");
hr = IUnknown_QueryInterface(unk_in_out, &IID_ISomethingFromDispatch, (void **)&sfd_in_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = ISomethingFromDispatch_anotherfn(sfd_in_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
ISomethingFromDispatch_Release(sfd_in_out);
release_iface(unk_out);
release_iface(unk_in_out);
release_iface(sfd1);
release_iface(sfd3);
}
testmode = 2;
unk_in = unk_out = unk_in_out = NULL;
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_PTR, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
todo_wine
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!unk_out, "[out] parameter should not have been set.\n");
if (hr == S_OK) {
hr = IUnknown_QueryInterface(unk_in_out, &IID_ISomethingFromDispatch, (void **)&sfd_in_out);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = ISomethingFromDispatch_anotherfn(sfd_in_out);
ok(hr == 0x01234567, "Got hr %#x.\n", hr);
ISomethingFromDispatch_Release(sfd_in_out);
release_iface(unk_in_out);
}
testmode = 3;
unk_in = unk_out = NULL;
sfd3 = create_disp_obj();
unk_in_out = (IUnknown *)sfd3;
IUnknown_AddRef(unk_in_out);
hr = IDispatch_Invoke(disp, DISPID_TM_IFACE_PTR, &IID_NULL, LOCALE_NEUTRAL,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
todo_wine {
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!unk_in_out, "[in, out] parameter should have been cleared.\n");
release_iface(sfd3);
}
}
static void test_typelibmarshal(void)
{
static const WCHAR szCat[] = { 'C','a','t',0 };
@ -2184,6 +2611,7 @@ todo_wine
test_marshal_basetypes(pWidget, pDispatch);
test_marshal_pointer(pWidget, pDispatch);
test_marshal_iface(pWidget, pDispatch);
IDispatch_Release(pDispatch);
IWidget_Release(pWidget);

View File

@ -59,6 +59,9 @@ enum IWidget_dispids
DISPID_TM_BASETYPES_OUT,
DISPID_TM_INT_PTR,
DISPID_TM_INT_PTR_PTR,
DISPID_TM_IFACE_IN,
DISPID_TM_IFACE_OUT,
DISPID_TM_IFACE_PTR,
};
static const int DISPID_TM_NEG_RESTRICTED = -26;
@ -95,6 +98,7 @@ library TestTypelib
[
odl,
oleautomation,
uuid(12345678-1234-4321-1234-121212121212)
]
interface ISomethingFromDispatch : IDispatch
@ -250,6 +254,15 @@ library TestTypelib
[id(DISPID_TM_INT_PTR_PTR)]
HRESULT int_ptr_ptr([in] int **in, [out] int **out, [in, out] int **in_out);
[id(DISPID_TM_IFACE_IN)]
HRESULT iface_in([in] IUnknown *unk, [in] IDispatch *disp, [in] ISomethingFromDispatch *sfd);
[id(DISPID_TM_IFACE_OUT)]
HRESULT iface_out([out] IUnknown **unk, [out] IDispatch **disp, [out] ISomethingFromDispatch **sfd);
[id(DISPID_TM_IFACE_PTR)]
HRESULT iface_ptr([in] ISomethingFromDispatch **in, [out] ISomethingFromDispatch **out, [in, out] ISomethingFromDispatch **in_out);
}
[