Signed-off-by: Zebediah Figura z.figura12@gmail.com --- This test may be better placed in ole32; I'm open to moving it.
dlls/rpcrt4/tests/Makefile.in | 5 +- dlls/rpcrt4/tests/cstub.c | 245 ++++++++++++++++++++++++++++++++++++++++-- dlls/rpcrt4/tests/cstub.idl | 37 +++++++ 3 files changed, 280 insertions(+), 7 deletions(-) create mode 100644 dlls/rpcrt4/tests/cstub.idl
diff --git a/dlls/rpcrt4/tests/Makefile.in b/dlls/rpcrt4/tests/Makefile.in index 5b80bc3..d8353b6 100644 --- a/dlls/rpcrt4/tests/Makefile.in +++ b/dlls/rpcrt4/tests/Makefile.in @@ -1,6 +1,7 @@ TESTDLL = rpcrt4.dll IMPORTS = oleaut32 ole32 rpcrt4 secur32 advapi32 EXTRAIDLFLAGS = --prefix-server=s_ +EXTRADEFS = -DPROXY_DELEGATION
C_SRCS = \ cstub.c \ @@ -10,4 +11,6 @@ C_SRCS = \ rpc_async.c \ server.c
-IDL_SRCS = server.idl +IDL_SRCS = \ + cstub.idl \ + server.idl diff --git a/dlls/rpcrt4/tests/cstub.c b/dlls/rpcrt4/tests/cstub.c index 7bed308..22d4569 100644 --- a/dlls/rpcrt4/tests/cstub.c +++ b/dlls/rpcrt4/tests/cstub.c @@ -19,11 +19,10 @@ */
#include <stdarg.h> +#include <stdio.h>
-#define PROXY_DELEGATION #define COBJMACROS
-#include "wine/test.h" #include <windef.h> #include <winbase.h> #include <winnt.h> @@ -35,10 +34,22 @@ #include "rpcdce.h" #include "rpcproxy.h"
+#include "wine/heap.h" +#include "wine/test.h" + +#include "cstub.h" + static CStdPSFactoryBuffer PSFactoryBuffer;
-CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer) -CSTDSTUBBUFFER2RELEASE(&PSFactoryBuffer) +static ULONG WINAPI test_CStdStubBuffer_Release(IRpcStubBuffer *This) +{ + return NdrCStdStubBuffer_Release(This, (IPSFactoryBuffer *)&PSFactoryBuffer); +} + +static ULONG WINAPI test_CStdStubBuffer2_Release(IRpcStubBuffer *This) +{ + return NdrCStdStubBuffer2_Release(This, (IPSFactoryBuffer *)&PSFactoryBuffer); +}
static GUID IID_if1 = {0x12345678, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}}; static GUID IID_if2 = {0x12345679, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}}; @@ -186,7 +197,18 @@ static CInterfaceStubVtbl if1_stub_vtbl = 5, &if1_table[-3] }, - { CStdStubBuffer_METHODS } + { + CStdStubBuffer_QueryInterface, + CStdStubBuffer_AddRef, + test_CStdStubBuffer_Release, + CStdStubBuffer_Connect, + CStdStubBuffer_Disconnect, + CStdStubBuffer_Invoke, + CStdStubBuffer_IsIIDSupported, + CStdStubBuffer_CountRefs, + CStdStubBuffer_DebugServerQueryInterface, + CStdStubBuffer_DebugServerRelease + } };
static CINTERFACE_PROXY_VTABLE(13) if2_proxy_vtbl = @@ -257,7 +279,7 @@ static CInterfaceStubVtbl if2_stub_vtbl = 13, &if2_table[-3] }, - { CStdStubBuffer_DELEGATING_METHODS } + { 0, 0, test_CStdStubBuffer2_Release, 0, 0, 0, 0, 0, 0, 0 } };
static CINTERFACE_PROXY_VTABLE(5) if3_proxy_vtbl = @@ -1194,9 +1216,219 @@ static void test_NdrDllRegisterProxy( void ) } }
+static HANDLE create_process(const char *arg) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si = {0}; + char cmdline[200]; + char **argv; + BOOL ret; + + si.cb = sizeof(si); + winetest_get_mainargs(&argv); + sprintf(cmdline, ""%s" %s %s", argv[0], argv[1], arg); + ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed: %u\n", GetLastError()); + CloseHandle(pi.hThread); + return pi.hProcess; +} + +DEFINE_GUID(CLSID_test1,0xdeadf00d,0x0001,0x44c7,0x85,0x0f,0x2a,0x0f,0x46,0x5c,0x0c,0x6c); + +static HRESULT WINAPI test1_QueryInterface(ITest1 *iface, REFIID iid, void **out) +{ + if (winetest_debug > 1) trace("%s\n", wine_dbgstr_guid(iid)); + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_ITest1)) + { + *out = iface; + return S_OK; + } + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test1_AddRef(ITest1 *iface) +{ + return 2; +} + +static ULONG WINAPI test1_Release(ITest1 *iface) +{ + return 1; +} + +static HRESULT WINAPI test1_GetClassID(ITest1 *iface, CLSID *clsid) +{ + *clsid = CLSID_test1; + return S_OK; +} + +static int WINAPI test1_square(ITest1 *iface, int x) +{ + return x * x; +} + +static const ITest1Vtbl test1_vtbl = +{ + test1_QueryInterface, + test1_AddRef, + test1_Release, + test1_GetClassID, + test1_square, +}; + +static HRESULT WINAPI test_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory)) + { + *out = iface; + return S_OK; + } + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_cf_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI test_cf_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI test_cf_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out) +{ + ITest1 *obj = heap_alloc(sizeof(*obj)); + + obj->lpVtbl = &test1_vtbl; + + return ITest1_QueryInterface(obj, iid, out); +} + +static HRESULT WINAPI test_cf_LockServer(IClassFactory *iface, BOOL lock) +{ + return S_OK; +} + +static const IClassFactoryVtbl test_cf_vtbl = +{ + test_cf_QueryInterface, + test_cf_AddRef, + test_cf_Release, + test_cf_CreateInstance, + test_cf_LockServer, +}; + +static IClassFactory test_cf = { &test_cf_vtbl }; + +extern CStdPSFactoryBuffer gPFactory; +extern const ProxyFileInfo * aProxyFileList; + +static void local_server_proc(void) +{ + DWORD obj_cookie, ps_cookie, index; + HANDLE stop_event, ready_event; + IPSFactoryBuffer *ps; + HRESULT hr; + + stop_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "wine_cstub_test_server_stop"); + ready_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "wine_cstub_test_server_ready"); + + CoInitialize(NULL); + + hr = CoRegisterClassObject(&CLSID_test1, (IUnknown *)&test_cf, + CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &obj_cookie); + ok(hr == S_OK, "got %#x\n", hr); + + hr = NdrDllGetClassObject(&CLSID_test_ps, &IID_IPSFactoryBuffer, (void **)&ps, + &aProxyFileList, &CLSID_test_ps, &gPFactory); + ok(hr == S_OK, "got %#x\n", hr); + + hr = CoRegisterClassObject(&CLSID_test_ps, (IUnknown *)ps, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &ps_cookie); + ok(hr == S_OK, "got %#x\n", hr); + + hr = CoRegisterPSClsid(&IID_ITest1, &CLSID_test_ps); + ok(hr == S_OK, "got %#x\n", hr); + + SetEvent(ready_event); + + hr = CoWaitForMultipleHandles(0, 1000, 1, &stop_event, &index); + ok(hr == S_OK, "got %#x\n", hr); + ok(!index, "got %u\n", index); + + hr = CoRevokeClassObject(ps_cookie); + ok(hr == S_OK, "got %#x\n", hr); + + hr = CoRevokeClassObject(obj_cookie); + ok(hr == S_OK, "got %#x\n", hr); + + CoUninitialize(); + ExitProcess(0); +} + +static void test_delegated_methods(void) +{ + HANDLE process, stop_event, ready_event; + IPSFactoryBuffer *ps; + ITest1 *test_obj; + DWORD ps_cookie; + CLSID clsid; + HRESULT hr; + int ret; + + stop_event = CreateEventA(NULL, TRUE, FALSE, "wine_cstub_test_server_stop"); + ready_event = CreateEventA(NULL, TRUE, FALSE, "wine_cstub_test_server_ready"); + + process = create_process("server"); + ok(!WaitForSingleObject(ready_event, 1000), "wait failed\n"); + + hr = NdrDllGetClassObject(&CLSID_test_ps, &IID_IPSFactoryBuffer, (void **)&ps, + &aProxyFileList, &CLSID_test_ps, &gPFactory); + ok(hr == S_OK, "got %#x\n", hr); + + hr = CoRegisterClassObject(&CLSID_test_ps, (IUnknown *)ps, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &ps_cookie); + ok(hr == S_OK, "got %#x\n", hr); + + hr = CoRegisterPSClsid(&IID_ITest1, &CLSID_test_ps); + ok(hr == S_OK, "got %#x\n", hr); + + hr = CoCreateInstance(&CLSID_test1, NULL, CLSCTX_LOCAL_SERVER, &IID_ITest1, (void **)&test_obj); + ok(hr == S_OK, "got %#x\n", hr); + + ret = ITest1_square(test_obj, 3); + ok(ret == 9, "got %d\n", ret); + + hr = ITest1_GetClassID(test_obj, &clsid); +todo_wine { + ok(hr == S_OK, "got %#x\n", hr); + ok(IsEqualGUID(&clsid, &CLSID_test1), "got %s\n", wine_dbgstr_guid(&clsid)); +} + + ITest1_Release(test_obj); + + SetEvent(stop_event); + ok(!WaitForSingleObject(process, 1000), "wait failed\n"); + + hr = CoRevokeClassObject(ps_cookie); + ok(hr == S_OK, "got %#x\n", hr); +} + START_TEST( cstub ) { IPSFactoryBuffer *ppsf; + int argc; + char **argv; + + argc = winetest_get_mainargs( &argv ); + if (argc > 2 && !strcmp(argv[2], "server")) + { + local_server_proc(); + return; + }
OleInitialize(NULL);
@@ -1209,6 +1441,7 @@ START_TEST( cstub ) test_Release(ppsf); test_delegating_Invoke(ppsf); test_NdrDllRegisterProxy(); + test_delegated_methods();
OleUninitialize(); } diff --git a/dlls/rpcrt4/tests/cstub.idl b/dlls/rpcrt4/tests/cstub.idl new file mode 100644 index 0000000..461bd87 --- /dev/null +++ b/dlls/rpcrt4/tests/cstub.idl @@ -0,0 +1,37 @@ +/* + * IDL to test COM object proxy/stub functions + * + * Copyright 2018 Zebediah Figura + * + * 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 + */ + +#pragma makedep proxy + +import "oleidl.idl"; + +[ + uuid(deadbeef-0001-44c7-850f-2a0f465c0c6c), + object +] +interface ITest1 : IPersist +{ + int square(int x); +} + +[ + uuid(deadbeef-ffff-44c7-850f-2a0f465c0c6c) +] +coclass test_ps { interface IPSFactoryBuffer; }
Delegated proxies pass the IID of the parent interface to NdrProxyGetBuffer(). However, this interface was never registered with ole32 on the server side, so calls to delegated methods will return RPC_S_UNKNOWN_IF. Therefore we have ole32 ignore the passed-in parameter and use the real proxy ID.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45673 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- It's not clear to me that this is the correct way to solve bug 45673. If this seems to be the wrong approach; I'd really appreciate some help on determining what the right approach is.
dlls/ole32/compobj_private.h | 2 +- dlls/ole32/marshal.c | 2 +- dlls/ole32/rpc.c | 6 ++++-- dlls/rpcrt4/tests/cstub.c | 2 -- 4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 212d328..1e564a3 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -210,7 +210,7 @@ struct dispatch_params;
void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, - const OXID_INFO *oxid_info, + const OXID_INFO *oxid_info, const IID *iid, DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, APARTMENT *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 7c0f541..6bfd47e 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -1290,7 +1290,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, { IRpcChannelBuffer *chanbuf; hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, - &proxy_manager->oxid_info, + &proxy_manager->oxid_info, riid, proxy_manager->dest_context, proxy_manager->dest_context_data, &chanbuf, apt); diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 9aa945b..bd4611d 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -109,6 +109,7 @@ typedef struct OXID oxid; /* apartment in which the channel is valid */ DWORD server_pid; /* id of server process */ HANDLE event; /* cached event handle */ + IID iid; /* IID of the proxy this belongs to */ } ClientRpcChannelBuffer;
struct dispatch_params @@ -650,7 +651,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
cif->Length = sizeof(RPC_CLIENT_INTERFACE); /* RPC interface ID = COM interface ID */ - cif->InterfaceId.SyntaxGUID = *riid; + cif->InterfaceId.SyntaxGUID = This->iid; /* COM objects always have a version of 0.0 */ cif->InterfaceId.SyntaxVersion.MajorVersion = 0; cif->InterfaceId.SyntaxVersion.MinorVersion = 0; @@ -1096,7 +1097,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
/* returns a channel buffer for proxies */ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, - const OXID_INFO *oxid_info, + const OXID_INFO *oxid_info, const IID *iid, DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, APARTMENT *apt) { @@ -1155,6 +1156,7 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, apartment_getoxid(apt, &This->oxid); This->server_pid = oxid_info->dwPid; This->event = NULL; + This->iid = *iid;
*chan = &This->super.IRpcChannelBuffer_iface;
diff --git a/dlls/rpcrt4/tests/cstub.c b/dlls/rpcrt4/tests/cstub.c index 22d4569..6b99e82 100644 --- a/dlls/rpcrt4/tests/cstub.c +++ b/dlls/rpcrt4/tests/cstub.c @@ -1403,10 +1403,8 @@ static void test_delegated_methods(void) ok(ret == 9, "got %d\n", ret);
hr = ITest1_GetClassID(test_obj, &clsid); -todo_wine { ok(hr == S_OK, "got %#x\n", hr); ok(IsEqualGUID(&clsid, &CLSID_test1), "got %s\n", wine_dbgstr_guid(&clsid)); -}
ITest1_Release(test_obj);
Signed-off-by: Huw Davies huw@codeweavers.com