X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=modules%2Frostests%2Fwinetests%2Fole32%2Fmarshal.c;h=22a67960120415167d0e1f67a8f65e59f57f7994;hp=2a29e66efebe7d9aa50abda84ba8a0e77e4d6c4d;hb=5c1bcfec6933973cf7f674f9073e44882002e575;hpb=b44b1afb813634b7e4da9cf79cd4e393a355f3ca diff --git a/modules/rostests/winetests/ole32/marshal.c b/modules/rostests/winetests/ole32/marshal.c index 2a29e66efeb..22a67960120 100644 --- a/modules/rostests/winetests/ole32/marshal.c +++ b/modules/rostests/winetests/ole32/marshal.c @@ -18,12 +18,49 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "precomp.h" - -#include - -DEFINE_GUID(CLSID_StdGlobalInterfaceTable,0x00000323,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); -DEFINE_GUID(CLSID_ManualResetEvent, 0x0000032c,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +#define _WIN32_DCOM +#define COBJMACROS +#define CONST_VTABLE + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "olectl.h" +#include "shlguid.h" +#include "shobjidl.h" + +#include "wine/test.h" +#include "wine/heap.h" + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +static const GUID CLSID_WineTestPSFactoryBuffer = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } }; +static const GUID CLSID_DfMarshal = { 0x0000030b, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; /* functions that are not present on all versions of Windows */ static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); @@ -37,6 +74,51 @@ static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID); #define ok_zero_external_conn() do {if (with_external_conn) ok(!external_connections, "got %d external connections\n", external_connections);} while(0); #define ok_last_release_closes(b) do {if (with_external_conn) ok(last_release_closes == b, "got %d expected %d\n", last_release_closes, b);} while(0); +#define OBJREF_SIGNATURE (0x574f454d) +#define OBJREF_STANDARD (0x1) +#define OBJREF_CUSTOM (0x4) + +typedef struct tagDUALSTRINGARRAY { + unsigned short wNumEntries; + unsigned short wSecurityOffset; + unsigned short aStringArray[1]; +} DUALSTRINGARRAY; + +typedef UINT64 OXID; +typedef UINT64 OID; +typedef GUID IPID; + +typedef struct tagSTDOBJREF { + ULONG flags; + ULONG cPublicRefs; + OXID oxid; + OID oid; + IPID ipid; +} STDOBJREF; + +typedef struct tagOBJREF { + ULONG signature; + ULONG flags; + GUID iid; + union { + struct OR_STANDARD { + STDOBJREF std; + DUALSTRINGARRAY saResAddr; + } u_standard; + struct OR_HANDLER { + STDOBJREF std; + CLSID clsid; + DUALSTRINGARRAY saResAddr; + } u_handler; + struct OR_CUSTOM { + CLSID clsid; + ULONG cbExtension; + ULONG size; + byte *pData; + } u_custom; + } u_objref; +} OBJREF; + static const IID IID_IWineTest = { 0x5201163f, @@ -268,26 +350,286 @@ static const IClassFactoryVtbl TestClassFactory_Vtbl = static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl }; +DEFINE_EXPECT(Invoke); +DEFINE_EXPECT(CreateStub); +DEFINE_EXPECT(CreateProxy); +DEFINE_EXPECT(GetWindow); +DEFINE_EXPECT(Disconnect); + +static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface) +{ + return 2; +} + +static ULONG WINAPI OleWindow_Release(IOleWindow *iface) +{ + return 1; +} + +static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd) +{ + CHECK_EXPECT(GetWindow); + *hwnd = (HWND)0xdeadbeef; + return S_OK; +} + +static const IOleWindowVtbl OleWindowVtbl = { + OleWindow_QueryInterface, + OleWindow_AddRef, + OleWindow_Release, + OleWindow_GetWindow, + /* not needed */ +}; + +static IOleWindow Test_OleWindow = { &OleWindowVtbl }; + +static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleClientSite)) + *ppv = iface; + else if (IsEqualGUID(riid, &IID_IOleWindow)) + *ppv = &Test_OleWindow; + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface) +{ + return 2; +} + +static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface) +{ + return 1; +} + +static const IOleClientSiteVtbl OleClientSiteVtbl = { + OleClientSite_QueryInterface, + OleClientSite_AddRef, + OleClientSite_Release, + /* we don't need the rest, we never call it */ +}; + +static IOleClientSite Test_OleClientSite = { &OleClientSiteVtbl }; + +typedef struct { + IRpcStubBuffer IRpcStubBuffer_iface; + LONG ref; + IRpcStubBuffer *buffer; +} StubBufferWrapper; + +static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface) +{ + return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface); +} + +static HRESULT WINAPI RpcStubBuffer_QueryInterface(IRpcStubBuffer *iface, REFIID riid, void **ppv) +{ + StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface); + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRpcStubBuffer, riid)) { + *ppv = &This->IRpcStubBuffer_iface; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface) +{ + StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI RpcStubBuffer_Release(IRpcStubBuffer *iface) +{ + StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface); + LONG ref = InterlockedDecrement(&This->ref); + if(!ref) { + IRpcStubBuffer_Release(This->buffer); + heap_free(This); + } + return ref; +} + +static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface) +{ + CHECK_EXPECT(Disconnect); +} + +static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE *_prpcmsg, + IRpcChannelBuffer *_pRpcChannelBuffer) +{ + StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface); + void *dest_context_data; + DWORD dest_context; + HRESULT hr; + + CHECK_EXPECT(Invoke); + + hr = IRpcChannelBuffer_GetDestCtx(_pRpcChannelBuffer, &dest_context, &dest_context_data); + ok(hr == S_OK, "GetDestCtx failed: %08x\n", hr); + ok(dest_context == MSHCTX_INPROC, "desc_context = %x\n", dest_context); + ok(!dest_context_data, "desc_context_data = %p\n", dest_context_data); + + return IRpcStubBuffer_Invoke(This->buffer, _prpcmsg, _pRpcChannelBuffer); +} + +static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID riid) +{ + ok(0, "unexpected call\n"); + return NULL; +} + +static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static void WINAPI RpcStubBuffer_DebugServerRelease(IRpcStubBuffer *iface, void *pv) +{ + ok(0, "unexpected call\n"); +} + +static const IRpcStubBufferVtbl RpcStubBufferVtbl = { + RpcStubBuffer_QueryInterface, + RpcStubBuffer_AddRef, + RpcStubBuffer_Release, + RpcStubBuffer_Connect, + RpcStubBuffer_Disconnect, + RpcStubBuffer_Invoke, + RpcStubBuffer_IsIIDSupported, + RpcStubBuffer_CountRefs, + RpcStubBuffer_DebugServerQueryInterface, + RpcStubBuffer_DebugServerRelease +}; + +static IPSFactoryBuffer *ps_factory_buffer; + +static HRESULT WINAPI PSFactoryBuffer_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPSFactoryBuffer)) + *ppv = iface; + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface) +{ + return 2; +} + +static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface) +{ + return 1; +} + +static HRESULT WINAPI PSFactoryBuffer_CreateProxy(IPSFactoryBuffer *iface, IUnknown *outer, + REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv) +{ + CHECK_EXPECT(CreateProxy); + return IPSFactoryBuffer_CreateProxy(ps_factory_buffer, outer, riid, ppProxy, ppv); +} + +static HRESULT WINAPI PSFactoryBuffer_CreateStub(IPSFactoryBuffer *iface, REFIID riid, + IUnknown *server, IRpcStubBuffer **ppStub) +{ + StubBufferWrapper *stub; + HRESULT hr; + + CHECK_EXPECT(CreateStub); + + ok(server == (IUnknown*)&Test_OleClientSite, "unexpected server %p\n", server); + + stub = heap_alloc(sizeof(*stub)); + stub->IRpcStubBuffer_iface.lpVtbl = &RpcStubBufferVtbl; + stub->ref = 1; + + hr = IPSFactoryBuffer_CreateStub(ps_factory_buffer, riid, server, &stub->buffer); + ok(hr == S_OK, "CreateStub failed: %08x\n", hr); + + *ppStub = &stub->IRpcStubBuffer_iface; + return S_OK; +} + +static IPSFactoryBufferVtbl PSFactoryBufferVtbl = +{ + PSFactoryBuffer_QueryInterface, + PSFactoryBuffer_AddRef, + PSFactoryBuffer_Release, + PSFactoryBuffer_CreateProxy, + PSFactoryBuffer_CreateStub +}; + +static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl }; + #define RELEASEMARSHALDATA WM_USER struct host_object_data { IStream *stream; - IID iid; + const IID *iid; IUnknown *object; MSHLFLAGS marshal_flags; - HANDLE marshal_event; IMessageFilter *filter; + IUnknown *register_object; + const CLSID *register_clsid; + HANDLE marshal_event; }; +#ifndef __REACTOS__ /* FIXME: Inspect */ +static IPSFactoryBuffer PSFactoryBuffer; +#endif + static DWORD CALLBACK host_object_proc(LPVOID p) { struct host_object_data *data = p; + DWORD registration_key; HRESULT hr; MSG msg; pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if(data->register_object) { + hr = CoRegisterClassObject(data->register_clsid, data->register_object, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key); + ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr); + } + if (data->filter) { IMessageFilter * prev_filter = NULL; @@ -296,7 +638,7 @@ static DWORD CALLBACK host_object_proc(LPVOID p) ok_ole_success(hr, CoRegisterMessageFilter); } - hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags); + hr = CoMarshalInterface(data->stream, data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags); ok_ole_success(hr, CoMarshalInterface); /* force the message queue to be created before signaling parent thread */ @@ -322,31 +664,27 @@ static DWORD CALLBACK host_object_proc(LPVOID p) return hr; } -static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread) +static DWORD start_host_object2(struct host_object_data *object_data, HANDLE *thread) { DWORD tid = 0; - HANDLE marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL); - 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 = marshal_event; - data->filter = filter; + struct host_object_data *data; + data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data)); + *data = *object_data; + data->marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL); *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid); /* wait for marshaling to complete before returning */ - ok( !WaitForSingleObject(marshal_event, 10000), "wait timed out\n" ); - CloseHandle(marshal_event); + ok( !WaitForSingleObject(data->marshal_event, 10000), "wait timed out\n" ); + CloseHandle(data->marshal_event); return tid; } 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); + struct host_object_data object_data = { stream, riid, object, marshal_flags }; + return start_host_object2(&object_data, thread); } /* asks thread to release the marshal data because it has to be done by the @@ -949,6 +1287,362 @@ static void test_marshal_proxy_mta_apartment_shutdown(void) pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); } +static void test_marshal_channel_buffer(void) +{ + DWORD registration_key; + IUnknown *proxy = NULL; + IOleWindow *ole_window; + HWND hwnd; + CLSID clsid; + DWORD tid; + HANDLE thread; + HRESULT hr; + + struct host_object_data object_data = { NULL, &IID_IOleClientSite, (IUnknown*)&Test_OleClientSite, + MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer, + &CLSID_WineTestPSFactoryBuffer }; + + cLocks = 0; + external_connections = 0; + + hr = CoGetPSClsid(&IID_IOleWindow, &clsid); + ok_ole_success(hr, "CoGetPSClsid"); + + hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, + (void **)&ps_factory_buffer); + ok_ole_success(hr, "CoGetClassObject"); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + tid = start_host_object2(&object_data, &thread); + + IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, CoUnmarshalInterface); + IStream_Release(object_data.stream); + + hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key); + ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr); + + hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer); + ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr); + + SET_EXPECT(CreateStub); + SET_EXPECT(CreateProxy); + hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window); + ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr); + CHECK_CALLED(CreateStub); + CHECK_CALLED(CreateProxy); + + SET_EXPECT(Invoke); + SET_EXPECT(GetWindow); + hr = IOleWindow_GetWindow(ole_window, &hwnd); + ok(hr == S_OK, "GetWindow failed: %08x\n", hr); + ok((DWORD)(DWORD_PTR)hwnd == 0xdeadbeef, "hwnd = %p\n", hwnd); + CHECK_CALLED(Invoke); + CHECK_CALLED(GetWindow); + + IOleWindow_Release(ole_window); + + SET_EXPECT(Disconnect); + IUnknown_Release(proxy); +todo_wine + CHECK_CALLED(Disconnect); + + hr = CoRevokeClassObject(registration_key); + ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr); + + end_host_object(tid, thread); +} + +static const CLSID *unmarshal_class; +DEFINE_EXPECT(CustomMarshal_GetUnmarshalClass); +DEFINE_EXPECT(CustomMarshal_GetMarshalSizeMax); +DEFINE_EXPECT(CustomMarshal_MarshalInterface); + +static HRESULT WINAPI CustomMarshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) { + *ppv = iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI CustomMarshal_AddRef(IMarshal *iface) +{ + return 2; +} + +static ULONG WINAPI CustomMarshal_Release(IMarshal *iface) +{ + return 1; +} + +static HRESULT WINAPI CustomMarshal_GetUnmarshalClass(IMarshal *iface, REFIID riid, + void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *clsid) +{ + CHECK_EXPECT(CustomMarshal_GetUnmarshalClass); + *clsid = *unmarshal_class; + return S_OK; +} + +static HRESULT WINAPI CustomMarshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid, + void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *size) +{ + CHECK_EXPECT(CustomMarshal_GetMarshalSizeMax); + ok(size != NULL, "size = NULL\n"); + + *size = 0; + return S_OK; +} + +static HRESULT WINAPI CustomMarshal_MarshalInterface(IMarshal *iface, IStream *stream, + REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) +{ + IMarshal *std_marshal; + STATSTG stat; + HRESULT hr; + + CHECK_EXPECT(CustomMarshal_MarshalInterface); + + if(unmarshal_class != &CLSID_StdMarshal) + return S_OK; + + hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT); + ok_ole_success(hr, IStream_Stat); + ok(U(stat.cbSize).LowPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).LowPart); + ok(U(stat.cbSize).HighPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).HighPart); + + hr = CoGetStandardMarshal(riid, (IUnknown*)iface, + dwDestContext, NULL, mshlflags, &std_marshal); + ok_ole_success(hr, CoGetStandardMarshal); + hr = IMarshal_MarshalInterface(std_marshal, stream, riid, pv, + dwDestContext, pvDestContext, mshlflags); + ok_ole_success(hr, IMarshal_MarshalInterface); + IMarshal_Release(std_marshal); + + return S_OK; +} + +static HRESULT WINAPI CustomMarshal_UnmarshalInterface(IMarshal *iface, + IStream *stream, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI CustomMarshal_ReleaseMarshalData(IMarshal *iface, IStream *stream) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI CustomMarshal_DisconnectObject(IMarshal *iface, DWORD res) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IMarshalVtbl CustomMarshalVtbl = +{ + CustomMarshal_QueryInterface, + CustomMarshal_AddRef, + CustomMarshal_Release, + CustomMarshal_GetUnmarshalClass, + CustomMarshal_GetMarshalSizeMax, + CustomMarshal_MarshalInterface, + CustomMarshal_UnmarshalInterface, + CustomMarshal_ReleaseMarshalData, + CustomMarshal_DisconnectObject +}; + +static IMarshal CustomMarshal = { &CustomMarshalVtbl }; + +static void test_StdMarshal_custom_marshaling(void) +{ + IStream *stream; + IUnknown *unk; + DWORD size; + HRESULT hr; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + unmarshal_class = &CLSID_StdMarshal; + SET_EXPECT(CustomMarshal_GetUnmarshalClass); + SET_EXPECT(CustomMarshal_MarshalInterface); + hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + CHECK_CALLED(CustomMarshal_GetUnmarshalClass); + CHECK_CALLED(CustomMarshal_MarshalInterface); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + hr = CoUnmarshalInterface(stream, &IID_IUnknown, (void**)&unk); + ok_ole_success(hr, CoUnmarshalInterface); + ok(unk == (IUnknown*)&CustomMarshal, "unk != &CustomMarshal\n"); + IUnknown_Release(unk); + IStream_Release(stream); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + SET_EXPECT(CustomMarshal_GetUnmarshalClass); + SET_EXPECT(CustomMarshal_MarshalInterface); + hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + CHECK_CALLED(CustomMarshal_GetUnmarshalClass); + CHECK_CALLED(CustomMarshal_MarshalInterface); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + hr = CoReleaseMarshalData(stream); + ok_ole_success(hr, CoReleaseMarshalData); + IStream_Release(stream); + + SET_EXPECT(CustomMarshal_GetMarshalSizeMax); + hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoGetMarshalSizeMax); + CHECK_CALLED(CustomMarshal_GetMarshalSizeMax); + ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF)); +} + +static void test_DfMarshal_custom_marshaling(void) +{ + DWORD size, read; + IStream *stream; + OBJREF objref; + HRESULT hr; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + unmarshal_class = &CLSID_DfMarshal; + SET_EXPECT(CustomMarshal_GetUnmarshalClass); + SET_EXPECT(CustomMarshal_GetMarshalSizeMax); + SET_EXPECT(CustomMarshal_MarshalInterface); + hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + CHECK_CALLED(CustomMarshal_GetUnmarshalClass); + CHECK_CALLED(CustomMarshal_GetMarshalSizeMax); + CHECK_CALLED(CustomMarshal_MarshalInterface); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData); + hr = IStream_Read(stream, &objref, size, &read); + ok_ole_success(hr, IStream_Read); + ok(read == size, "read = %d, expected %d\n", read, size); + ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n", + objref.signature); + ok(objref.flags == OBJREF_CUSTOM, "objref.flags = %x\n", objref.flags); + ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n", + wine_dbgstr_guid(&objref.iid)); + ok(IsEqualIID(&objref.u_objref.u_custom.clsid, &CLSID_DfMarshal), + "custom.clsid = %s\n", wine_dbgstr_guid(&objref.u_objref.u_custom.clsid)); + ok(!objref.u_objref.u_custom.cbExtension, "custom.cbExtension = %d\n", + objref.u_objref.u_custom.cbExtension); + ok(!objref.u_objref.u_custom.size, "custom.size = %d\n", + objref.u_objref.u_custom.size); + + IStream_Release(stream); + + SET_EXPECT(CustomMarshal_GetMarshalSizeMax); + hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoGetMarshalSizeMax); + CHECK_CALLED(CustomMarshal_GetMarshalSizeMax); + ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF)); +} + +static void test_CoGetStandardMarshal(void) +{ + DUALSTRINGARRAY *dualstringarr; + STDOBJREF *stdobjref; + OBJREF objref; + IMarshal *marshal; + DWORD size, read; + IStream *stream; + IUnknown *unk; + CLSID clsid; + HRESULT hr; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + hr = CoGetStandardMarshal(&IID_IUnknown, &Test_Unknown, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &marshal); + ok_ole_success(hr, CoGetStandardMarshal); + + hr = IMarshal_GetUnmarshalClass(marshal, &IID_IUnknown, &Test_Unknown, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid); + ok_ole_success(hr, IMarshal_GetUnmarshalClass); + ok(IsEqualGUID(&clsid, &CLSID_StdMarshal), "clsid = %s\n", wine_dbgstr_guid(&clsid)); + + hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IUnknown, &Test_Unknown, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &size); + ok_ole_success(hr, IMarshal_GetMarshalSizeMax); + hr = CoGetMarshalSizeMax(&read, &IID_IUnknown, &Test_Unknown, + MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoGetMarshalSizeMax); + ok(size == read, "IMarshal_GetMarshalSizeMax size = %d, expected %d\n", size, read); + + hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown, + &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, IMarshal_MarshalInterface); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + size = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray); + hr = IStream_Read(stream, &objref, size, &read); + ok_ole_success(hr, IStream_Read); + ok(read == size, "read = %d, expected %d\n", read, size); + ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n", + objref.signature); + ok(objref.flags == OBJREF_STANDARD, "objref.flags = %x\n", objref.flags); + ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n", + wine_dbgstr_guid(&objref.iid)); + stdobjref = &objref.u_objref.u_standard.std; + ok(stdobjref->flags == 0, "stdobjref.flags = %d\n", stdobjref->flags); + ok(stdobjref->cPublicRefs == 5, "stdobjref.cPublicRefs = %d\n", + stdobjref->cPublicRefs); + dualstringarr = &objref.u_objref.u_standard.saResAddr; + ok(dualstringarr->wNumEntries == 0, "dualstringarr.wNumEntries = %d\n", + dualstringarr->wNumEntries); + ok(dualstringarr->wSecurityOffset == 0, "dualstringarr.wSecurityOffset = %d\n", + dualstringarr->wSecurityOffset); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + hr = IMarshal_UnmarshalInterface(marshal, stream, &IID_IUnknown, (void**)&unk); + ok_ole_success(hr, IMarshal_UnmarshalInterface); + IUnknown_Release(unk); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown, + &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, IMarshal_MarshalInterface); + + hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, IStream_Seek); + hr = IMarshal_ReleaseMarshalData(marshal, stream); + ok_ole_success(hr, IMarshal_ReleaseMarshalData); + IStream_Release(stream); + + IMarshal_Release(marshal); +} struct ncu_params { LPSTREAM stream; @@ -1952,25 +2646,27 @@ static IMessageFilter MessageFilter = { &MessageFilter_Vtbl }; static void test_message_filter(void) { HRESULT hr; - IStream *pStream = NULL; IClassFactory *cf = NULL; DWORD tid; IUnknown *proxy = NULL; IMessageFilter *prev_filter = NULL; HANDLE thread; + struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, + MSHLFLAGS_NORMAL, &MessageFilter }; + cLocks = 0; - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream); ok_ole_success(hr, CreateStreamOnHGlobal); - tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread); + tid = start_host_object2(&object_data, &thread); ok_more_than_one_lock(); - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf); + IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf); ok_ole_success(hr, CoUnmarshalInterface); - IStream_Release(pStream); + IStream_Release(object_data.stream); ok_more_than_one_lock(); @@ -2511,6 +3207,7 @@ static void test_freethreadedmarshaler(void) IStream *pStream; IUnknown *pProxy; static const LARGE_INTEGER llZero; + CLSID clsid; cLocks = 0; hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown); @@ -2524,6 +3221,12 @@ static void test_freethreadedmarshaler(void) /* inproc normal marshaling */ + hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory, + &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid); + ok_ole_success(hr, IMarshal_GetUnmarshalClass); + ok(IsEqualIID(&clsid, &CLSID_InProcFreeMarshaler), "clsid = %s\n", + wine_dbgstr_guid(&clsid)); + hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok_ole_success(hr, IMarshal_MarshalInterface); @@ -2540,27 +3243,6 @@ static void test_freethreadedmarshaler(void) ok_no_locks(); -/* native doesn't allow us to unmarshal or release the stream data, - * presumably because it wants us to call CoMarshalInterface instead */ - if (0) - { - /* local normal marshaling */ - - IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); - hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL); - ok_ole_success(hr, IMarshal_MarshalInterface); - - ok_more_than_one_lock(); - - test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL); - - IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); - hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream); - ok_ole_success(hr, IMarshal_ReleaseMarshalData); - - ok_no_locks(); - } - /* inproc table-strong marshaling */ IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); @@ -2638,6 +3320,28 @@ static void test_freethreadedmarshaler(void) ok_no_locks(); + /* local normal marshaling */ + + hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory, + &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL, &clsid); + ok_ole_success(hr, IMarshal_GetUnmarshalClass); + ok(IsEqualIID(&clsid, &CLSID_StdMarshal), "clsid = %s\n", + wine_dbgstr_guid(&clsid)); + + IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); + hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, IMarshal_MarshalInterface); + + ok_more_than_one_lock(); + + test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL); + + IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); + hr = CoReleaseMarshalData(pStream); + ok_ole_success(hr, CoReleaseMarshalData); + + ok_no_locks(); + IStream_Release(pStream); IMarshal_Release(pFTMarshal); } @@ -3406,6 +4110,169 @@ static void test_manualresetevent(void) ok(!ref, "Got nonzero ref: %d\n", ref); } +static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param) +{ + IStream *stream = param; + IClassFactory *cf; + IUnknown *proxy; + HRESULT hr; + + IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf); + ok_ole_success(hr, CoUnmarshalInterface); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, IClassFactory_CreateInstance); + + IUnknown_Release(proxy); + + /* But if we initialize an STA in this apartment, it becomes the wrong one. */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr); + + CoUninitialize(); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + IClassFactory_Release(cf); + + ok_no_locks(); + ok_zero_external_conn(); + ok_last_release_closes(TRUE); + return 0; +} + +static DWORD CALLBACK implicit_mta_use_proc(void *param) +{ + IClassFactory *cf = param; + IUnknown *proxy; + HRESULT hr; + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, IClassFactory_CreateInstance); + + IUnknown_Release(proxy); + + /* But if we initialize an STA in this apartment, it becomes the wrong one. */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr); + + CoUninitialize(); + return 0; +} + +struct implicit_mta_marshal_data +{ + IStream *stream; + HANDLE start; + HANDLE stop; +}; + +static DWORD CALLBACK implicit_mta_marshal_proc(void *param) +{ + struct implicit_mta_marshal_data *data = param; + HRESULT hr; + + hr = CoMarshalInterface(data->stream, &IID_IClassFactory, + (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + + SetEvent(data->start); + + ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n"); + return 0; +} + +static void test_implicit_mta(void) +{ + struct implicit_mta_marshal_data data; + HANDLE host_thread, thread; + IClassFactory *cf; + IUnknown *proxy; + IStream *stream; + HRESULT hr; + DWORD tid; + + cLocks = 0; + external_connections = 0; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + /* Firstly: we can unmarshal and use an object while in the implicit MTA. */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + CloseHandle(thread); + + IStream_Release(stream); + end_host_object(tid, host_thread); + + /* Secondly: we can unmarshal an object into the real MTA and then use it + * from the implicit MTA. */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf); + ok_ole_success(hr, CoUnmarshalInterface); + + thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + CloseHandle(thread); + + IClassFactory_Release(cf); + IStream_Release(stream); + + ok_no_locks(); + ok_non_zero_external_conn(); + ok_last_release_closes(TRUE); + + end_host_object(tid, host_thread); + + /* Thirdly: we can marshal an object from the implicit MTA and then + * unmarshal it into the real one. */ + data.start = CreateEventA(NULL, FALSE, FALSE, NULL); + data.stop = CreateEventA(NULL, FALSE, FALSE, NULL); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL); + ok(!WaitForSingleObject(data.start, 1000), "wait failed\n"); + + IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf); + ok_ole_success(hr, CoUnmarshalInterface); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, IClassFactory_CreateInstance); + + IUnknown_Release(proxy); + + SetEvent(data.stop); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + CloseHandle(thread); + + IStream_Release(data.stream); + + CoUninitialize(); +} + static const char *debugstr_iid(REFIID riid) { static char name[256]; @@ -3413,8 +4280,8 @@ static const char *debugstr_iid(REFIID riid) WCHAR bufferW[39]; char buffer[39]; LONG name_size = sizeof(name); - StringFromGUID2(riid, bufferW, sizeof(bufferW)/sizeof(bufferW[0])); - WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer, sizeof(buffer), NULL, NULL); + StringFromGUID2(riid, bufferW, ARRAY_SIZE(bufferW)); + WideCharToMultiByte(CP_ACP, 0, bufferW, ARRAY_SIZE(bufferW), buffer, sizeof(buffer), NULL, NULL); if (RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS) { memcpy(name, buffer, sizeof(buffer)); @@ -3679,13 +4546,15 @@ static IChannelHook TestChannelHook = { &TestChannelHookVtbl }; static void test_channel_hook(void) { - IStream *pStream = NULL; IClassFactory *cf = NULL; DWORD tid; IUnknown *proxy = NULL; HANDLE thread; HRESULT hr; + struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, + MSHLFLAGS_NORMAL, &MessageFilter }; + hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook); ok_ole_success(hr, CoRegisterChannelHook); @@ -3694,17 +4563,17 @@ static void test_channel_hook(void) cLocks = 0; - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream); ok_ole_success(hr, CreateStreamOnHGlobal); - tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread); + tid = start_host_object2(&object_data, &thread); server_tid = tid; ok_more_than_one_lock(); - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf); + IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf); ok_ole_success(hr, CoUnmarshalInterface); - IStream_Release(pStream); + IStream_Release(object_data.stream); ok_more_than_one_lock(); @@ -3752,6 +4621,7 @@ START_TEST(marshal) register_test_window(); test_cocreateinstance_proxy(); + test_implicit_mta(); pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); @@ -3789,6 +4659,10 @@ START_TEST(marshal) with_external_conn = !with_external_conn; } while (with_external_conn); + test_marshal_channel_buffer(); + test_StdMarshal_custom_marshaling(); + test_DfMarshal_custom_marshaling(); + test_CoGetStandardMarshal(); test_hresult_marshaling(); test_proxy_used_in_wrong_thread(); test_message_filter();