+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);
+}