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