Signed-off-by: Jactry Zeng jzeng@codeweavers.com
--- v3: - Make creation of group manager safe. v2: - Add CRITICAL_SECTION for struct group_manager; - Use DISPID_VALUE and DISPID_NEWENUM instead; - Improve tests. --- dlls/comsvcs/Makefile.in | 3 +- dlls/comsvcs/comsvcs_private.h | 38 ++++++++ dlls/comsvcs/main.c | 28 +++--- dlls/comsvcs/property.c | 163 +++++++++++++++++++++++++++++++++ dlls/comsvcs/tests/Makefile.in | 3 +- dlls/comsvcs/tests/property.c | 115 +++++++++++++++++++++++ include/comsvcs.idl | 65 +++++++++++++ 7 files changed, 401 insertions(+), 14 deletions(-) create mode 100644 dlls/comsvcs/comsvcs_private.h create mode 100644 dlls/comsvcs/property.c create mode 100644 dlls/comsvcs/tests/property.c
diff --git a/dlls/comsvcs/Makefile.in b/dlls/comsvcs/Makefile.in index 7845400cb2..b4a4244bce 100644 --- a/dlls/comsvcs/Makefile.in +++ b/dlls/comsvcs/Makefile.in @@ -5,7 +5,8 @@ IMPORTS = ole32 uuid EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ - main.c + main.c \ + property.c
IDL_SRCS = \ comsvcs_classes.idl \ diff --git a/dlls/comsvcs/comsvcs_private.h b/dlls/comsvcs/comsvcs_private.h new file mode 100644 index 0000000000..6d299d3a88 --- /dev/null +++ b/dlls/comsvcs/comsvcs_private.h @@ -0,0 +1,38 @@ +/* + * Copyright 2020 Jactry Zeng for CodeWeavers + * + * 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 + */ + +#ifndef _COMSVCS_PRIVATE_H_ +#define _COMSVCS_PRIVATE_H_ + +#define COBJMACROS + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "ole2.h" +#include "rpcproxy.h" +#include "comsvcs.h" +#include "initguid.h" + +#include "wine/heap.h" +#include "wine/debug.h" + +HRESULT WINAPI group_manager_create(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out); + +#endif diff --git a/dlls/comsvcs/main.c b/dlls/comsvcs/main.c index 9ab77dfced..1d3f7db174 100644 --- a/dlls/comsvcs/main.c +++ b/dlls/comsvcs/main.c @@ -18,18 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#define COBJMACROS - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "ole2.h" -#include "rpcproxy.h" -#include "comsvcs.h" -#include "wine/heap.h" -#include "wine/debug.h" -#include "initguid.h" +#include "comsvcs_private.h" #include "comsvcs_classes.h"
WINE_DEFAULT_DEBUG_CHANNEL(comsvcs); @@ -1027,8 +1016,18 @@ static const IClassFactoryVtbl newmoniker_cf_vtbl = comsvcscf_LockServer };
+static const IClassFactoryVtbl group_manager_cf_vtbl = +{ + comsvcscf_QueryInterface, + comsvcscf_AddRef, + comsvcscf_Release, + group_manager_create, + comsvcscf_LockServer +}; + static IClassFactory DispenserManageFactory = { &comsvcscf_vtbl }; static IClassFactory NewMonikerFactory = { &newmoniker_cf_vtbl }; +static IClassFactory GroupManagerFactory = { &group_manager_cf_vtbl };
/****************************************************************** * DllGetClassObject @@ -1045,6 +1044,11 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) TRACE("(CLSID_NewMoniker %s %p)\n", debugstr_guid(riid), ppv); return IClassFactory_QueryInterface(&NewMonikerFactory, riid, ppv); } + else if (IsEqualGUID(&CLSID_SharedPropertyGroupManager, rclsid)) + { + TRACE("(CLSID_SharedPropertyGroupManager %s %p)\n", debugstr_guid(riid), ppv); + return IClassFactory_QueryInterface(&GroupManagerFactory, riid, ppv); + }
FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/comsvcs/property.c b/dlls/comsvcs/property.c new file mode 100644 index 0000000000..3c9917c926 --- /dev/null +++ b/dlls/comsvcs/property.c @@ -0,0 +1,163 @@ +/* + * Copyright 2020 Jactry Zeng for CodeWeavers + * + * 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 + */ + +#include <comsvcs_private.h> + +WINE_DEFAULT_DEBUG_CHANNEL(comsvcs); + +struct group_manager +{ + ISharedPropertyGroupManager ISharedPropertyGroupManager_iface; + LONG refcount; +}; + +static struct group_manager *group_manager = NULL; + +static inline struct group_manager *impl_from_ISharedPropertyGroupManager(ISharedPropertyGroupManager *iface) +{ + return CONTAINING_RECORD(iface, struct group_manager, ISharedPropertyGroupManager_iface); +} + +static HRESULT WINAPI group_manager_QueryInterface(ISharedPropertyGroupManager *iface, REFIID riid, void **out) +{ + struct group_manager *manager = impl_from_ISharedPropertyGroupManager(iface); + + TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDispatch) + || IsEqualGUID(riid, &IID_ISharedPropertyGroupManager)) + { + *out = &manager->ISharedPropertyGroupManager_iface; + IUnknown_AddRef((IUnknown *)*out); + return S_OK; + } + + WARN("%s not implemented.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI group_manager_AddRef(ISharedPropertyGroupManager *iface) +{ + struct group_manager *manager = impl_from_ISharedPropertyGroupManager(iface); + ULONG refcount = InterlockedIncrement(&manager->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI group_manager_Release(ISharedPropertyGroupManager *iface) +{ + struct group_manager *manager = impl_from_ISharedPropertyGroupManager(iface); + ULONG refcount = InterlockedDecrement(&manager->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static HRESULT WINAPI group_manager_GetTypeInfoCount(ISharedPropertyGroupManager *iface, UINT *info) +{ + FIXME("iface %p, info %p: stub.\n", iface, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI group_manager_GetTypeInfo(ISharedPropertyGroupManager *iface, UINT index, LCID lcid, ITypeInfo **info) +{ + FIXME("iface %p, index %u, lcid %u, info %p: stub.\n", iface, index, lcid, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI group_manager_GetIDsOfNames(ISharedPropertyGroupManager *iface, REFIID riid, LPOLESTR *names, UINT count, + LCID lcid, DISPID *dispid) +{ + FIXME("iface %p, riid %s, names %p, count %u, lcid %u, dispid %p: stub.\n", + iface, debugstr_guid(riid), names, count, lcid, dispid); + + return E_NOTIMPL; +} + +static HRESULT WINAPI group_manager_Invoke(ISharedPropertyGroupManager *iface, DISPID member, REFIID riid, LCID lcid, + WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *except, UINT *argerr) +{ + FIXME("iface %p, member %u, riid %s, lcid %u, flags %x, params %p, result %p, except %p, argerr %p: stub.\n", + iface, member, debugstr_guid(riid), lcid, flags, params, result, except, argerr); + return E_NOTIMPL; +} + +static HRESULT WINAPI group_manager_CreatePropertyGroup(ISharedPropertyGroupManager *iface, BSTR name, LONG *isolation, + LONG *release, VARIANT_BOOL *exists, ISharedPropertyGroup **group) +{ + FIXME("iface %p, name %s, isolation %p, release %p, exists %p, group %p: stub.\n", + iface, debugstr_w(name), isolation, release, exists, group); + return E_NOTIMPL; +} + +static HRESULT WINAPI group_manager_get_Group(ISharedPropertyGroupManager *iface, BSTR name, ISharedPropertyGroup **group) +{ + FIXME("iface %p, name %s, group %p: stub.\n", iface, debugstr_w(name), group); + return E_NOTIMPL; +} + +static HRESULT WINAPI group_manager_get__NewEnum(ISharedPropertyGroupManager *iface, IUnknown **retval) +{ + FIXME("iface %p, retval %p: stub.\n", iface, retval); + return E_NOTIMPL; +} + +static const ISharedPropertyGroupManagerVtbl group_manager_vtbl = +{ + group_manager_QueryInterface, + group_manager_AddRef, + group_manager_Release, + group_manager_GetTypeInfoCount, + group_manager_GetTypeInfo, + group_manager_GetIDsOfNames, + group_manager_Invoke, + group_manager_CreatePropertyGroup, + group_manager_get_Group, + group_manager_get__NewEnum +}; + +HRESULT WINAPI group_manager_create(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) +{ + struct group_manager *manager; + + if (outer) + return CLASS_E_NOAGGREGATION; + + if (!group_manager) + { + manager = heap_alloc(sizeof(*manager)); + if (!manager) + { + *out = NULL; + return E_OUTOFMEMORY; + } + manager->ISharedPropertyGroupManager_iface.lpVtbl = &group_manager_vtbl; + manager->refcount = 1; + + if (InterlockedCompareExchangePointer((void **)&group_manager, manager, NULL)) + { + heap_free(manager); + } + } + return ISharedPropertyGroupManager_QueryInterface(&group_manager->ISharedPropertyGroupManager_iface, riid, out); +} diff --git a/dlls/comsvcs/tests/Makefile.in b/dlls/comsvcs/tests/Makefile.in index 86da9fda66..1d9146ba5b 100644 --- a/dlls/comsvcs/tests/Makefile.in +++ b/dlls/comsvcs/tests/Makefile.in @@ -2,4 +2,5 @@ TESTDLL = comsvcs.dll IMPORTS = uuid oleaut32 ole32
C_SRCS = \ - comsvcs.c + comsvcs.c \ + property.c diff --git a/dlls/comsvcs/tests/property.c b/dlls/comsvcs/tests/property.c new file mode 100644 index 0000000000..adad7bd539 --- /dev/null +++ b/dlls/comsvcs/tests/property.c @@ -0,0 +1,115 @@ +/* + * Copyright 2020 Jactry Zeng for CodeWeavers + * + * 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 + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "comsvcs.h" + +#include "wine/test.h" + +static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); +} + +static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI outer_AddRef(IUnknown *iface) +{ + ok(0, "Unexpected call.\n"); + return 1; +} + +static ULONG WINAPI outer_Release(IUnknown *iface) +{ + ok(0, "Unexpected call.\n"); + return 0; +} + +static const IUnknownVtbl outer_vtbl = +{ + outer_QueryInterface, + outer_AddRef, + outer_Release, +}; + +static IUnknown test_outer = {&outer_vtbl}; + +static void test_interfaces(void) +{ + ISharedPropertyGroupManager *manager, *manager1; + ULONG refcount, expected_refcount; + IDispatch *dispatch; + IUnknown *unk; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SharedPropertyGroupManager, &test_outer, CLSCTX_INPROC_SERVER, + &IID_ISharedPropertyGroupManager, (void **)&manager); + ok(hr == CLASS_E_NOAGGREGATION, "Got hr %#x.\n", hr); + + hr = CoCreateInstance(&CLSID_SharedPropertyGroupManager, NULL, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + expected_refcount = get_refcount(unk) + 1; + hr = IUnknown_QueryInterface(unk, &IID_ISharedPropertyGroupManager, (void **)&manager); + ok(hr == S_OK, "Got hr %#x.\n", hr); + refcount = get_refcount(unk); + ok(refcount == expected_refcount, "Got refcount: %u, expected %u.\n", refcount, expected_refcount); + + expected_refcount = get_refcount(manager) + 1; + hr = CoCreateInstance(&CLSID_SharedPropertyGroupManager, NULL, CLSCTX_INPROC_SERVER, + &IID_ISharedPropertyGroupManager, (void **)&manager1); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(manager1 == manager, "Got wrong pointer: %p.\n", manager1); + refcount = get_refcount(manager1); + ok(refcount == expected_refcount, "Got refcount: %u, expected %u.\n", refcount, expected_refcount); + refcount = get_refcount(manager); + ok(refcount == expected_refcount, "Got refcount: %u, expected %u.\n", refcount, expected_refcount); + ISharedPropertyGroupManager_Release(manager1); + + hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void **)&dispatch); + ok(hr == S_OK, "Got hr %#x.\n", hr); + refcount = get_refcount(dispatch); + ok(refcount == expected_refcount, "Got refcount: %u, expected %u.\n", refcount, expected_refcount); + refcount = get_refcount(manager); + ok(refcount == expected_refcount, "Got refcount: %u, expected %u.\n", refcount, expected_refcount); + + IDispatch_Release(dispatch); + IUnknown_Release(unk); + ISharedPropertyGroupManager_Release(manager); +} + +START_TEST(property) +{ + CoInitialize(NULL); + + test_interfaces(); + + CoUninitialize(); +} diff --git a/include/comsvcs.idl b/include/comsvcs.idl index d64af1f5a8..ee1fede360 100644 --- a/include/comsvcs.idl +++ b/include/comsvcs.idl @@ -37,6 +37,8 @@ typedef DWORD_PTR TRANSID; ] library COMSVCSLib { + importlib("stdole2.tlb"); + [ object, hidden, @@ -96,4 +98,67 @@ library COMSVCSLib { [default] interface IDispenserManager; }; + + [ + object, + hidden, + local, + uuid(2a005c01-a5de-11cf-9e66-00aa00a3f464), + pointer_default(unique) + ] + interface ISharedProperty : IDispatch + { + [id(DISPID_VALUE), propget] + HRESULT Value([out, retval] VARIANT *value); + [id(DISPID_VALUE), propput] + HRESULT Value([in] VARIANT value); + } + + [ + object, + hidden, + local, + uuid(2a005c07-a5de-11cf-9e66-00aa00a3f464), + pointer_default(unique) + ] + interface ISharedPropertyGroup : IDispatch + { + [id(0x00000001)] + HRESULT CreatePropertyByPosition([in] int index, [out] VARIANT_BOOL *exists, [out, retval] ISharedProperty **property); + [id(0x00000002), propget] + HRESULT PropertyByPosition([in] int index, [out, retval] ISharedProperty **property); + [id(0x00000003)] + HRESULT CreateProperty([in] BSTR name, [out] VARIANT_BOOL *exists, [out, retval] ISharedProperty **property); + [id(0x00000004), propget] + HRESULT Property([in] BSTR name, [out, retval] ISharedProperty **property); + } + + [ + object, + hidden, + local, + uuid(2a005c0d-a5de-11cf-9e66-00aa00a3f464), + pointer_default(unique) + ] + interface ISharedPropertyGroupManager : IDispatch + { + [id(0x00000001)] + HRESULT CreatePropertyGroup([in] BSTR name, [in, out] LONG *isolation, [in, out] LONG *release, + [out] VARIANT_BOOL *exists, [out, retval] ISharedPropertyGroup **group); + [id(0x00000002), propget] + HRESULT Group([in] BSTR name, [out, retval] ISharedPropertyGroup **group); + [id(DISPID_NEWENUM), propget] + HRESULT _NewEnum([out, retval] IUnknown **retval); + } + + [ + uuid(2a005c11-a5de-11cf-9e66-00aa00a3f464), + progid("MTxSpm.SharedPropertyGroupManager.1"), + vi_progid("MTxSpm.SharedPropertyGroupManager"), + threading(both) + ] + coclass SharedPropertyGroupManager + { + [default] interface ISharedPropertyGroupManager; + } }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77759
Your paranoid android.
=== debiant (32 bit report) ===
comsvcs: property.c:73: Test failed: Got hr 0x80040154. property.c:77: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004036ed).
Report validation errors: comsvcs:property crashed (c0000005)
=== debiant (32 bit French report) ===
comsvcs: property.c:73: Test failed: Got hr 0x80040154. property.c:77: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004036ed).
Report validation errors: comsvcs:property crashed (c0000005)
=== debiant (32 bit Japanese:Japan report) ===
comsvcs: property.c:73: Test failed: Got hr 0x80040154. property.c:77: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004036ed).
Report validation errors: comsvcs:property crashed (c0000005)
=== debiant (32 bit Chinese:China report) ===
comsvcs: property.c:73: Test failed: Got hr 0x80040154. property.c:77: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004036ed).
Report validation errors: comsvcs:property crashed (c0000005)
=== debiant (32 bit WoW report) ===
comsvcs: property.c:73: Test failed: Got hr 0x80040154. property.c:77: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004036ed).
Report validation errors: comsvcs:property crashed (c0000005)
=== debiant (64 bit WoW report) ===
comsvcs: property.c:73: Test failed: Got hr 0x80040154. property.c:77: Test failed: Got hr 0x80040154. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004036ed).
Report validation errors: comsvcs:property crashed (c0000005)
I think this looks fine, expect for idl changes that affect generated typelib. We might want to have matching arguments names for that, because that type information also ends up in there as I recall.