Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2020
- 78 participants
- 638 discussions
17 Aug '20
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/comsvcs/comsvcs_private.h | 2 +
dlls/comsvcs/property.c | 200 ++++++++++++++++++++++++++++++++-
dlls/comsvcs/tests/property.c | 76 +++++++++++++
3 files changed, 276 insertions(+), 2 deletions(-)
diff --git a/dlls/comsvcs/comsvcs_private.h b/dlls/comsvcs/comsvcs_private.h
index eee6e9938c..3eeb9d751a 100644
--- a/dlls/comsvcs/comsvcs_private.h
+++ b/dlls/comsvcs/comsvcs_private.h
@@ -38,6 +38,7 @@ enum tid_t
NULL_tid,
ISharedPropertyGroupManager_tid,
ISharedPropertyGroup_tid,
+ ISharedProperty_tid,
LAST_tid
};
@@ -46,6 +47,7 @@ static REFIID tid_ids[] =
&IID_NULL,
&IID_ISharedPropertyGroupManager,
&IID_ISharedPropertyGroup,
+ &IID_ISharedProperty,
};
HRESULT get_typeinfo(enum tid_t tid, ITypeInfo **typeinfo);
diff --git a/dlls/comsvcs/property.c b/dlls/comsvcs/property.c
index 83bacc7b49..e7b9fd8628 100644
--- a/dlls/comsvcs/property.c
+++ b/dlls/comsvcs/property.c
@@ -20,10 +20,19 @@
WINE_DEFAULT_DEBUG_CHANNEL(comsvcs);
+struct shared_property
+{
+ ISharedProperty ISharedProperty_iface;
+ LONG refcount;
+ BSTR name;
+};
+
struct property_group
{
ISharedPropertyGroup ISharedPropertyGroup_iface;
ISharedPropertyGroupManager *parent;
+ struct shared_property *properties;
+ size_t capacity, count;
LONG isolation, release;
LONG refcount;
BSTR name;
@@ -50,6 +59,11 @@ static inline struct property_group *impl_from_ISharedPropertyGroup(ISharedPrope
return CONTAINING_RECORD(iface, struct property_group, ISharedPropertyGroup_iface);
}
+static inline struct shared_property *impl_from_ISharedProperty(ISharedProperty *iface)
+{
+ return CONTAINING_RECORD(iface, struct shared_property, ISharedProperty_iface);
+}
+
static inline BOOL comsvcs_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
{
size_t new_capacity, max_capacity;
@@ -81,6 +95,136 @@ static inline BOOL comsvcs_array_reserve(void **elements, size_t *capacity, size
return TRUE;
}
+static HRESULT WINAPI shared_property_QueryInterface(ISharedProperty *iface, REFIID riid, void **out)
+{
+ struct shared_property *property = impl_from_ISharedProperty(iface);
+
+ TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+ *out = NULL;
+ if (IsEqualGUID(riid, &IID_IUnknown)
+ || IsEqualGUID(riid, &IID_IDispatch)
+ || IsEqualGUID(riid, &IID_ISharedProperty))
+ {
+ *out = &property->ISharedProperty_iface;
+ IUnknown_AddRef((IUnknown*)*out);
+
+ return S_OK;
+ }
+
+ WARN("%s not implemented.\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI shared_property_AddRef(ISharedProperty *iface)
+{
+ struct shared_property *property = impl_from_ISharedProperty(iface);
+ ULONG refcount = InterlockedIncrement(&property->refcount);
+
+ TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI shared_property_Release(ISharedProperty *iface)
+{
+ struct shared_property *property = impl_from_ISharedProperty(iface);
+ ULONG refcount = InterlockedDecrement(&property->refcount);
+
+ TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ SysFreeString(property->name);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI shared_property_GetTypeInfoCount(ISharedProperty *iface, UINT *info)
+{
+ TRACE("iface %p, info %p.\n", iface, info);
+
+ if (!info)
+ return E_INVALIDARG;
+ *info = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI shared_property_GetTypeInfo(ISharedProperty *iface, UINT index, LCID lcid, ITypeInfo **info)
+{
+ HRESULT hr;
+
+ TRACE("iface %p, index %u, lcid %u, info %p.\n", iface, index, lcid, info);
+
+ if (index)
+ return DISP_E_BADINDEX;
+
+ hr = get_typeinfo(ISharedProperty_tid, info);
+ if (SUCCEEDED(hr))
+ ITypeInfo_AddRef(*info);
+ return hr;
+}
+
+static HRESULT WINAPI shared_property_GetIDsOfNames(ISharedProperty *iface, REFIID riid, LPOLESTR *names, UINT count,
+ LCID lcid, DISPID *dispid)
+{
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("iface %p, riid %s, names %p, count %u, lcid %u, dispid %p.\n",
+ iface, debugstr_guid(riid), names, count, lcid, dispid);
+
+ hr = get_typeinfo(ISharedProperty_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
+ ITypeInfo_Release(typeinfo);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI shared_property_Invoke(ISharedProperty *iface, DISPID member, REFIID riid, LCID lcid,
+ WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *except, UINT *argerr)
+{
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("iface %p, member %u, riid %s, lcid %u, flags %x, params %p, result %p, except %p, argerr %p.\n",
+ iface, member, debugstr_guid(riid), lcid, flags, params, result, except, argerr);
+
+ hr = get_typeinfo(ISharedProperty_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ hr = ITypeInfo_Invoke(typeinfo, iface, member, flags, params, result, except, argerr);
+ return hr;
+}
+
+static HRESULT WINAPI shared_property_get_Value(ISharedProperty *iface, VARIANT *value)
+{
+ FIXME("iface %p, value %p: stub.\n", iface, value);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI shared_property_put_Value(ISharedProperty *iface, VARIANT value)
+{
+ FIXME("iface %p, value %s: stub.\n", iface, debugstr_variant(&value));
+ return E_NOTIMPL;
+}
+
+static const ISharedPropertyVtbl shared_property_vtbl =
+{
+ shared_property_QueryInterface,
+ shared_property_AddRef,
+ shared_property_Release,
+ shared_property_GetTypeInfoCount,
+ shared_property_GetTypeInfo,
+ shared_property_GetIDsOfNames,
+ shared_property_Invoke,
+ shared_property_get_Value,
+ shared_property_put_Value
+};
+
static HRESULT WINAPI property_group_QueryInterface(ISharedPropertyGroup *iface, REFIID riid, void **out)
{
struct property_group *group = impl_from_ISharedPropertyGroup(iface);
@@ -211,11 +355,53 @@ static HRESULT WINAPI property_group_get_PropertyByPosition(ISharedPropertyGroup
return E_NOTIMPL;
}
+
+static struct shared_property *find_shared_property(struct property_group *group, BSTR name)
+{
+ int index;
+
+ for (index = 0; index < group->count; index++)
+ {
+ if (!lstrcmpW(group->properties[index].name, name))
+ return &group->properties[index];
+ }
+ return NULL;
+}
+
static HRESULT WINAPI property_group_CreateProperty(ISharedPropertyGroup *iface, BSTR name, VARIANT_BOOL *exists,
ISharedProperty **property)
{
- FIXME("iface %p, name %s, exists %p, property %p: stub.\n", iface, debugstr_w(name), exists, property);
- return E_NOTIMPL;
+ struct property_group *group = impl_from_ISharedPropertyGroup(iface);
+ struct shared_property *shared_property;
+ HRESULT hr;
+
+ TRACE("iface %p, name %s, exists %p, property %p.\n", iface, debugstr_w(name), exists, property);
+
+ shared_property = find_shared_property(group, name);
+ if (!shared_property)
+ {
+ if (!comsvcs_array_reserve((void **)&group->properties, &group->capacity, group->count + 1,
+ sizeof(*group->properties)))
+ return E_OUTOFMEMORY;
+
+ shared_property = &group->properties[group->count];
+ shared_property->refcount = 1;
+ shared_property->name = SysAllocString(name);
+ shared_property->ISharedProperty_iface.lpVtbl = &shared_property_vtbl;
+
+ group->count++;
+ *exists = FALSE;
+ *property = &shared_property->ISharedProperty_iface;
+ hr = S_OK;
+ }
+ else
+ {
+ *exists = TRUE;
+ hr = ISharedProperty_QueryInterface(&shared_property->ISharedProperty_iface,
+ &IID_ISharedProperty, (void **)property);
+ }
+
+ return hr;
}
static HRESULT WINAPI property_group_get_Property(ISharedPropertyGroup *iface, BSTR name, ISharedProperty **property)
@@ -385,6 +571,16 @@ static HRESULT WINAPI group_manager_CreatePropertyGroup(ISharedPropertyGroupMana
return E_OUTOFMEMORY;
property_group = &manager->property_groups[manager->count];
+
+ property_group->capacity = 0;
+ property_group->count = 0;
+ if (!comsvcs_array_reserve((void **)&property_group->properties, &property_group->capacity, 2,
+ sizeof(*property_group->properties)))
+ {
+ heap_free(manager->property_groups);
+ return E_OUTOFMEMORY;
+ }
+
property_group->ISharedPropertyGroup_iface.lpVtbl = &property_group_vtbl;
property_group->parent = iface;
property_group->isolation = *isolation;
diff --git a/dlls/comsvcs/tests/property.c b/dlls/comsvcs/tests/property.c
index fa83a49b94..971e1f4aed 100644
--- a/dlls/comsvcs/tests/property.c
+++ b/dlls/comsvcs/tests/property.c
@@ -308,12 +308,88 @@ static void test_property_group(void)
ISharedPropertyGroupManager_Release(manager);
}
+static void test_shared_property(void)
+{
+ ISharedProperty *property, *property1;
+ ISharedPropertyGroupManager *manager;
+ ULONG refcount, expected_refcount;
+ ISharedPropertyGroup *group;
+ BSTR name, property_name;
+ LONG isolation, release;
+ VARIANT_BOOL exists;
+ IDispatch *dispatch;
+ HRESULT hr;
+ struct test_name_id test_name_ids[] =
+ {
+ {L"Value", 0x0},
+ };
+
+ hr = CoCreateInstance(&CLSID_SharedPropertyGroupManager, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ISharedPropertyGroupManager, (void **)&manager);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ name = SysAllocString(L"testgroupname");
+ isolation = 0;
+ release = 0;
+ exists = FALSE;
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, &exists, &group);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ SysFreeString(name);
+
+ property_name = SysAllocString(L"testpropertyname");
+ exists = TRUE;
+ expected_refcount = get_refcount(group);
+ hr = ISharedPropertyGroup_CreateProperty(group, property_name, &exists, &property);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!exists, "Got unexpected value: %d.\n", exists);
+ refcount = get_refcount(group);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+
+ hr = ISharedPropertyGroup_get_PropertyByPosition(group, 0, &property1);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = ISharedPropertyGroup_get_PropertyByPosition(group, 1, &property1);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ exists = FALSE;
+ expected_refcount = get_refcount(property) + 1;
+ hr = ISharedPropertyGroup_CreateProperty(group, property_name, &exists, &property1);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!!exists, "Got unexpected value: %d.\n", exists);
+ refcount = get_refcount(property);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ expected_refcount--;
+ ISharedProperty_Release(property1);
+ refcount = get_refcount(property);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+
+ expected_refcount = get_refcount(property) + 1;
+ property1 = NULL;
+ hr = ISharedPropertyGroup_get_Property(group, property_name, &property1);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(property1 == property, "Got wrong pointer %p.\n", property);
+ refcount = get_refcount(property);
+ todo_wine ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ if (property1)
+ ISharedProperty_Release(property1);
+ SysFreeString(property_name);
+
+ hr = ISharedProperty_QueryInterface(property, &IID_IDispatch, (void **)&dispatch);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ TEST_TYPEINFO(dispatch, test_name_ids, ARRAY_SIZE(test_name_ids), &IID_ISharedProperty);
+ IDispatch_Release(dispatch);
+
+ ISharedProperty_Release(property);
+ ISharedPropertyGroup_Release(group);
+ ISharedPropertyGroupManager_Release(manager);
+}
+
START_TEST(property)
{
CoInitialize(NULL);
test_interfaces();
test_property_group();
+ test_shared_property();
CoUninitialize();
}
--
2.28.0
2
1
17 Aug '20
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/comsvcs/property.c | 16 ++++++++++++++--
dlls/comsvcs/tests/property.c | 25 ++++++++++++++++++++++++-
2 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/dlls/comsvcs/property.c b/dlls/comsvcs/property.c
index 6026fd8cc1..83bacc7b49 100644
--- a/dlls/comsvcs/property.c
+++ b/dlls/comsvcs/property.c
@@ -412,8 +412,20 @@ static HRESULT WINAPI group_manager_CreatePropertyGroup(ISharedPropertyGroupMana
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;
+ struct group_manager *manager = impl_from_ISharedPropertyGroupManager(iface);
+ struct property_group *property_group;
+
+ TRACE("iface %p, name %s, group %p.\n", iface, debugstr_w(name), group);
+
+ if (!name || !group)
+ return E_POINTER;
+
+ property_group = find_propery_group(manager, name);
+ if (!property_group)
+ return E_INVALIDARG;
+
+ return ISharedPropertyGroup_QueryInterface(&property_group->ISharedPropertyGroup_iface,
+ &IID_ISharedPropertyGroup, (void **)group);
}
static HRESULT WINAPI group_manager_get__NewEnum(ISharedPropertyGroupManager *iface, IUnknown **retval)
diff --git a/dlls/comsvcs/tests/property.c b/dlls/comsvcs/tests/property.c
index 9573def737..fa83a49b94 100644
--- a/dlls/comsvcs/tests/property.c
+++ b/dlls/comsvcs/tests/property.c
@@ -166,7 +166,7 @@ static void test_interfaces(void)
static void test_property_group(void)
{
- ISharedPropertyGroup *group, *group1;
+ ISharedPropertyGroup *group, *group1, *group2;
ISharedPropertyGroupManager *manager;
ULONG refcount, expected_refcount;
LONG isolation, release;
@@ -268,6 +268,29 @@ static void test_property_group(void)
TEST_TYPEINFO(dispatch, test_name_ids, ARRAY_SIZE(test_name_ids), &IID_ISharedPropertyGroup);
IDispatch_Release(dispatch);
+ hr = ISharedPropertyGroupManager_get_Group(manager, NULL, &group2);
+ ok(hr == E_POINTER, "Got hr %#x.\n", hr);
+
+ name = SysAllocString(L"nonexistgroup");
+ hr = ISharedPropertyGroupManager_get_Group(manager, name, &group2);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ SysFreeString(name);
+
+ name = SysAllocString(L"testgroupname");
+ hr = ISharedPropertyGroupManager_get_Group(manager, name, NULL);
+ ok(hr == E_POINTER, "Got hr %#x.\n", hr);
+
+ expected_refcount = get_refcount(manager);
+ hr = ISharedPropertyGroupManager_get_Group(manager, name, &group2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(group2 == group, "Got unexpected pointer %p.\n", group2);
+ refcount = get_refcount(group);
+ ok(refcount == 2, "Got unexpected refcount: %d.\n", refcount);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ ISharedPropertyGroup_Release(group2);
+ SysFreeString(name);
+
expected_refcount = get_refcount(manager);
ISharedPropertyGroup_Release(group1);
refcount = get_refcount(manager);
--
2.28.0
2
1
[PATCH 3/5] comsvcs: Implement ISharedPropertyGroupManager_CreatePropertyGroup().
by Jactry Zeng 17 Aug '20
by Jactry Zeng 17 Aug '20
17 Aug '20
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/comsvcs/comsvcs_private.h | 2 +
dlls/comsvcs/property.c | 277 ++++++++++++++++++++++++++++++++-
dlls/comsvcs/tests/property.c | 122 +++++++++++++++
3 files changed, 399 insertions(+), 2 deletions(-)
diff --git a/dlls/comsvcs/comsvcs_private.h b/dlls/comsvcs/comsvcs_private.h
index 8a67bcffd8..eee6e9938c 100644
--- a/dlls/comsvcs/comsvcs_private.h
+++ b/dlls/comsvcs/comsvcs_private.h
@@ -37,6 +37,7 @@ enum tid_t
{
NULL_tid,
ISharedPropertyGroupManager_tid,
+ ISharedPropertyGroup_tid,
LAST_tid
};
@@ -44,6 +45,7 @@ static REFIID tid_ids[] =
{
&IID_NULL,
&IID_ISharedPropertyGroupManager,
+ &IID_ISharedPropertyGroup,
};
HRESULT get_typeinfo(enum tid_t tid, ITypeInfo **typeinfo);
diff --git a/dlls/comsvcs/property.c b/dlls/comsvcs/property.c
index 0fc78e233f..6026fd8cc1 100644
--- a/dlls/comsvcs/property.c
+++ b/dlls/comsvcs/property.c
@@ -20,9 +20,21 @@
WINE_DEFAULT_DEBUG_CHANNEL(comsvcs);
+struct property_group
+{
+ ISharedPropertyGroup ISharedPropertyGroup_iface;
+ ISharedPropertyGroupManager *parent;
+ LONG isolation, release;
+ LONG refcount;
+ BSTR name;
+};
+
struct group_manager
{
ISharedPropertyGroupManager ISharedPropertyGroupManager_iface;
+ struct property_group *property_groups;
+ size_t capacity;
+ size_t count;
LONG refcount;
};
@@ -33,6 +45,200 @@ static inline struct group_manager *impl_from_ISharedPropertyGroupManager(IShare
return CONTAINING_RECORD(iface, struct group_manager, ISharedPropertyGroupManager_iface);
}
+static inline struct property_group *impl_from_ISharedPropertyGroup(ISharedPropertyGroup *iface)
+{
+ return CONTAINING_RECORD(iface, struct property_group, ISharedPropertyGroup_iface);
+}
+
+static inline BOOL comsvcs_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
+{
+ size_t new_capacity, max_capacity;
+ void *new_elements;
+
+ if (count <= *capacity)
+ return TRUE;
+
+ max_capacity = ~(SIZE_T)0 / size;
+ if (count > max_capacity)
+ return FALSE;
+
+ new_capacity = max(4, *capacity);
+ while (new_capacity < count && new_capacity <= max_capacity / 2)
+ new_capacity *= 2;
+ if (new_capacity < count)
+ new_capacity = max_capacity;
+
+ if (!*elements)
+ new_elements = heap_alloc_zero(new_capacity * size);
+ else
+ new_elements = heap_realloc(*elements, new_capacity * size);
+ if (!new_elements)
+ return FALSE;
+
+ *elements = new_elements;
+ *capacity = new_capacity;
+
+ return TRUE;
+}
+
+static HRESULT WINAPI property_group_QueryInterface(ISharedPropertyGroup *iface, REFIID riid, void **out)
+{
+ struct property_group *group = impl_from_ISharedPropertyGroup(iface);
+
+ TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+ *out = NULL;
+ if (IsEqualGUID(riid, &IID_IUnknown)
+ || IsEqualGUID(riid, &IID_IDispatch)
+ || IsEqualGUID(riid, &IID_ISharedPropertyGroup))
+ {
+ *out = &group->ISharedPropertyGroup_iface;
+ IUnknown_AddRef((IUnknown*)*out);
+
+ return S_OK;
+ }
+
+ WARN("%s not implemented.\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI property_group_AddRef(ISharedPropertyGroup *iface)
+{
+ struct property_group *group = impl_from_ISharedPropertyGroup(iface);
+ ULONG refcount = InterlockedIncrement(&group->refcount);
+
+ TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI property_group_Release(ISharedPropertyGroup *iface)
+{
+ struct property_group *group = impl_from_ISharedPropertyGroup(iface);
+ ULONG refcount = InterlockedDecrement(&group->refcount);
+
+ TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ struct group_manager *manager = impl_from_ISharedPropertyGroupManager(group->parent);
+ size_t count, index;
+
+ SysFreeString(group->name);
+
+ index = group - manager->property_groups;
+ manager->count--;
+ count = manager->count - index;
+ if (count)
+ memmove(&manager->property_groups[index], &manager->property_groups[index + 1], count * sizeof(*manager->property_groups));
+
+ ISharedPropertyGroupManager_Release(group->parent);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI property_group_GetTypeInfoCount(ISharedPropertyGroup *iface, UINT *info)
+{
+ TRACE("iface %p, info %p.\n", iface, info);
+
+ if (!info)
+ return E_INVALIDARG;
+ *info = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI property_group_GetTypeInfo(ISharedPropertyGroup *iface, UINT index, LCID lcid, ITypeInfo **info)
+{
+ HRESULT hr;
+
+ TRACE("iface %p, index %u, lcid %u, info %p.\n", iface, index, lcid, info);
+
+ if (index)
+ return DISP_E_BADINDEX;
+
+ hr = get_typeinfo(ISharedPropertyGroup_tid, info);
+ if (SUCCEEDED(hr))
+ ITypeInfo_AddRef(*info);
+ return hr;
+}
+
+static HRESULT WINAPI property_group_GetIDsOfNames(ISharedPropertyGroup *iface, REFIID riid, LPOLESTR *names, UINT count,
+ LCID lcid, DISPID *dispid)
+{
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("iface %p, riid %s, names %p, count %u, lcid %u, dispid %p.\n",
+ iface, debugstr_guid(riid), names, count, lcid, dispid);
+
+ hr = get_typeinfo(ISharedPropertyGroup_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
+ ITypeInfo_Release(typeinfo);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI property_group_Invoke(ISharedPropertyGroup *iface, DISPID member, REFIID riid, LCID lcid,
+ WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *except, UINT *argerr)
+{
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("iface %p, member %u, riid %s, lcid %u, flags %x, params %p, result %p, except %p, argerr %p.\n",
+ iface, member, debugstr_guid(riid), lcid, flags, params, result, except, argerr);
+
+ hr = get_typeinfo(ISharedPropertyGroup_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ hr = ITypeInfo_Invoke(typeinfo, iface, member, flags, params, result, except, argerr);
+ return hr;
+}
+
+static HRESULT WINAPI property_group_CreatePropertyByPosition(ISharedPropertyGroup *iface, int index,
+ VARIANT_BOOL *exists, ISharedProperty **property)
+{
+ FIXME("iface %p, index %d, exisits %p, property %p: stub.\n",
+ iface, index, exists, property);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_group_get_PropertyByPosition(ISharedPropertyGroup *iface, int index, ISharedProperty **property)
+{
+ FIXME("iface %p, index %d, property %p: stub.\n", iface, index, property);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_group_CreateProperty(ISharedPropertyGroup *iface, BSTR name, VARIANT_BOOL *exists,
+ ISharedProperty **property)
+{
+ FIXME("iface %p, name %s, exists %p, property %p: stub.\n", iface, debugstr_w(name), exists, property);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_group_get_Property(ISharedPropertyGroup *iface, BSTR name, ISharedProperty **property)
+{
+ FIXME("iface %p, name %s, property %p: stub.\n", iface, debugstr_w(name), property);
+ return E_NOTIMPL;
+}
+
+static const ISharedPropertyGroupVtbl property_group_vtbl =
+{
+ property_group_QueryInterface,
+ property_group_AddRef,
+ property_group_Release,
+ property_group_GetTypeInfoCount,
+ property_group_GetTypeInfo,
+ property_group_GetIDsOfNames,
+ property_group_Invoke,
+ property_group_CreatePropertyByPosition,
+ property_group_get_PropertyByPosition,
+ property_group_CreateProperty,
+ property_group_get_Property,
+};
+
static HRESULT WINAPI group_manager_QueryInterface(ISharedPropertyGroupManager *iface, REFIID riid, void **out)
{
struct group_manager *manager = impl_from_ISharedPropertyGroupManager(iface);
@@ -73,6 +279,7 @@ static ULONG WINAPI group_manager_Release(ISharedPropertyGroupManager *iface)
if (!refcount)
{
+ heap_free(manager->property_groups);
heap_free(manager);
group_manager = NULL;
}
@@ -139,12 +346,68 @@ static HRESULT WINAPI group_manager_Invoke(ISharedPropertyGroupManager *iface, D
return hr;
}
+static struct property_group *find_propery_group(struct group_manager *manager, BSTR name)
+{
+ int index;
+
+ for (index = 0; index < manager->count; index++)
+ {
+ if (!lstrcmpW(manager->property_groups[index].name, name))
+ return &manager->property_groups[index];
+ }
+ return NULL;
+}
+
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",
+ struct group_manager *manager = impl_from_ISharedPropertyGroupManager(iface);
+ struct property_group *property_group;
+ HRESULT hr;
+
+ TRACE("iface %p, name %s, isolation %p, release %p, exists %p, group %p.\n",
iface, debugstr_w(name), isolation, release, exists, group);
- return E_NOTIMPL;
+
+ if (!name)
+ return E_POINTER;
+
+ if (*isolation > 1 || *release > 1)
+ return E_INVALIDARG;
+
+ if (*isolation || *release)
+ FIXME("Unsopported mode: isolation %d, release %d.\n", *isolation, *release);
+
+ property_group = find_propery_group(manager, name);
+ if (!property_group)
+ {
+ if (!comsvcs_array_reserve((void **)&manager->property_groups, &manager->capacity, manager->count + 1,
+ sizeof(*manager->property_groups)))
+ return E_OUTOFMEMORY;
+
+ property_group = &manager->property_groups[manager->count];
+ property_group->ISharedPropertyGroup_iface.lpVtbl = &property_group_vtbl;
+ property_group->parent = iface;
+ property_group->isolation = *isolation;
+ property_group->release = *release;
+ property_group->refcount = 1;
+ property_group->name = SysAllocString(name);
+
+ manager->count++;
+ *exists = FALSE;
+ *group = &property_group->ISharedPropertyGroup_iface;
+ ISharedPropertyGroupManager_AddRef(property_group->parent);
+ hr = S_OK;
+ }
+ else
+ {
+ *exists = TRUE;
+ *isolation = property_group->isolation;
+ *release = property_group->release;
+ hr = ISharedPropertyGroup_QueryInterface(&property_group->ISharedPropertyGroup_iface,
+ &IID_ISharedPropertyGroup, (void **)group);
+ }
+
+ return hr;
}
static HRESULT WINAPI group_manager_get_Group(ISharedPropertyGroupManager *iface, BSTR name, ISharedPropertyGroup **group)
@@ -191,6 +454,16 @@ HRESULT WINAPI group_manager_create(IClassFactory *iface, IUnknown *outer, REFII
group_manager->ISharedPropertyGroupManager_iface.lpVtbl = &group_manager_vtbl;
group_manager->refcount = 1;
+ group_manager->capacity = 0;
+ group_manager->count = 0;
+ group_manager->property_groups = NULL;
+
+ if (!comsvcs_array_reserve((void **)&group_manager->property_groups, &group_manager->capacity, 2,
+ sizeof(*group_manager->property_groups)))
+ {
+ heap_free(group_manager);
+ return E_OUTOFMEMORY;
+ }
}
hr = ISharedPropertyGroupManager_QueryInterface(&group_manager->ISharedPropertyGroupManager_iface, riid, out);
diff --git a/dlls/comsvcs/tests/property.c b/dlls/comsvcs/tests/property.c
index 6d78cd39cd..9573def737 100644
--- a/dlls/comsvcs/tests/property.c
+++ b/dlls/comsvcs/tests/property.c
@@ -164,11 +164,133 @@ static void test_interfaces(void)
ISharedPropertyGroupManager_Release(manager);
}
+static void test_property_group(void)
+{
+ ISharedPropertyGroup *group, *group1;
+ ISharedPropertyGroupManager *manager;
+ ULONG refcount, expected_refcount;
+ LONG isolation, release;
+ VARIANT_BOOL exists;
+ IDispatch *dispatch;
+ HRESULT hr;
+ BSTR name;
+ struct test_name_id test_name_ids[] =
+ {
+ {L"CreatePropertyByPosition", 0x1},
+ {L"PropertyByPosition", 0x2},
+ {L"CreateProperty", 0x3},
+ {L"Property", 0x4},
+ };
+
+ hr = CoCreateInstance(&CLSID_SharedPropertyGroupManager, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ISharedPropertyGroupManager, (void **)&manager);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, NULL, &isolation, &release, &exists, &group);
+ ok(hr == E_POINTER, "Got hr %#x.\n", hr);
+
+ name = SysAllocString(L"testgroupname");
+ isolation = 2;
+ release = 0;
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, &exists, &group);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ /* Crash on Windows */
+ if (0)
+ {
+ ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, NULL, &release, &exists, &group1);
+ ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, NULL, &exists, &group1);
+ ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, NULL, &group1);
+ }
+
+ isolation = 0;
+ release = 2;
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, &exists, &group);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ name = SysAllocString(L"testgroupname");
+ isolation = 0;
+ release = 0;
+ exists = TRUE;
+ expected_refcount = get_refcount(manager) + 1;
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, &exists, &group);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!exists, "Got unexpected value %d.\n", exists);
+ refcount = get_refcount(group);
+ ok(refcount == 1, "Got unexpected refcount: %d.\n", refcount);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ ISharedPropertyGroup_AddRef(group);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ ISharedPropertyGroup_Release(group);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+
+ /* Create an existing group */
+ isolation = 1;
+ release = 1;
+ expected_refcount = get_refcount(manager);
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, &exists, &group1);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!!exists, "Got unexpected value %d.\n", exists);
+ ok(!isolation, "Got unexpected value %d.\n", isolation);
+ ok(!release, "Got unexpected value %d.\n", release);
+ ok(group == group1, "Got unexpected pointer: %p.\n", group1);
+ refcount = get_refcount(group);
+ ok(refcount == 2, "Got unexpected refcount: %d.\n", refcount);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ ISharedPropertyGroup_Release(group1);
+ refcount = get_refcount(group);
+ ok(refcount == 1, "Got unexpected refcount: %d.\n", refcount);
+ SysFreeString(name);
+
+ name = SysAllocString(L"testgroupname2");
+ isolation = 0;
+ release = 1;
+ exists = TRUE;
+ expected_refcount = get_refcount(manager) + 1;
+ hr = ISharedPropertyGroupManager_CreatePropertyGroup(manager, name, &isolation, &release, &exists, &group1);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(!exists, "Got unexpected value %d.\n", exists);
+ refcount = get_refcount(group1);
+ todo_wine ok(refcount == 2, "Got unexpected refcount: %d.\n", refcount);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ SysFreeString(name);
+
+ hr = ISharedPropertyGroup_QueryInterface(group, &IID_IDispatch, (void **)&dispatch);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ TEST_TYPEINFO(dispatch, test_name_ids, ARRAY_SIZE(test_name_ids), &IID_ISharedPropertyGroup);
+ IDispatch_Release(dispatch);
+
+ expected_refcount = get_refcount(manager);
+ ISharedPropertyGroup_Release(group1);
+ refcount = get_refcount(manager);
+ todo_wine ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ expected_refcount = get_refcount(manager) - 1;
+ ISharedPropertyGroup_Release(group1);
+ refcount = get_refcount(manager);
+ todo_wine ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+
+ expected_refcount = get_refcount(manager) - 1;
+ ISharedPropertyGroup_Release(group);
+ refcount = get_refcount(manager);
+ ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+
+ ISharedPropertyGroupManager_Release(manager);
+}
+
START_TEST(property)
{
CoInitialize(NULL);
test_interfaces();
+ test_property_group();
CoUninitialize();
}
--
2.28.0
3
2
[PATCH 2/5] comsvcs: Add IDispatch support for ISharedPropertyGroupManager.
by Jactry Zeng 17 Aug '20
by Jactry Zeng 17 Aug '20
17 Aug '20
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/comsvcs/Makefile.in | 2 +-
dlls/comsvcs/comsvcs_private.h | 15 ++++++++
dlls/comsvcs/main.c | 68 ++++++++++++++++++++++++++++++++++
dlls/comsvcs/property.c | 46 +++++++++++++++++++----
dlls/comsvcs/tests/property.c | 56 ++++++++++++++++++++++++++++
5 files changed, 178 insertions(+), 9 deletions(-)
diff --git a/dlls/comsvcs/Makefile.in b/dlls/comsvcs/Makefile.in
index b4a4244bce..82a496ea9c 100644
--- a/dlls/comsvcs/Makefile.in
+++ b/dlls/comsvcs/Makefile.in
@@ -1,6 +1,6 @@
MODULE = comsvcs.dll
IMPORTLIB = comsvcs
-IMPORTS = ole32 uuid
+IMPORTS = ole32 oleaut32 uuid
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/comsvcs/comsvcs_private.h b/dlls/comsvcs/comsvcs_private.h
index 6d299d3a88..8a67bcffd8 100644
--- a/dlls/comsvcs/comsvcs_private.h
+++ b/dlls/comsvcs/comsvcs_private.h
@@ -33,6 +33,21 @@
#include "wine/heap.h"
#include "wine/debug.h"
+enum tid_t
+{
+ NULL_tid,
+ ISharedPropertyGroupManager_tid,
+ LAST_tid
+};
+
+static REFIID tid_ids[] =
+{
+ &IID_NULL,
+ &IID_ISharedPropertyGroupManager,
+};
+
+HRESULT get_typeinfo(enum tid_t tid, ITypeInfo **typeinfo);
+
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 1d3f7db174..9f1deb7155 100644
--- a/dlls/comsvcs/main.c
+++ b/dlls/comsvcs/main.c
@@ -361,6 +361,71 @@ static HRESULT WINAPI dispenser_manager_cf_CreateInstance(IClassFactory *iface,
return ret;
}
+static ITypeLib *typelib;
+static ITypeInfo *typeinfos[LAST_tid];
+
+static HRESULT load_typelib(void)
+{
+ ITypeLib *tl;
+ HRESULT hr;
+
+ if (typelib)
+ return S_OK;
+
+ hr = LoadRegTypeLib(&LIBID_COMSVCSLib, 1, 0, LOCALE_SYSTEM_DEFAULT, &tl);
+ if (FAILED(hr))
+ {
+ ERR("LoadRegTypeLib failed: %#x.\n", hr);
+ return hr;
+ }
+
+ if (InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
+ ITypeLib_Release(tl);
+ return hr;
+}
+
+HRESULT get_typeinfo(enum tid_t tid, ITypeInfo **typeinfo)
+{
+ HRESULT hr;
+
+ hr = load_typelib();
+ if (FAILED(hr))
+ return hr;
+
+ if (!typeinfos[tid])
+ {
+ ITypeInfo *ti;
+
+ hr = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti);
+ if (FAILED(hr))
+ {
+ ERR("GetTypeInfoOfGuid(%s) failed: %#x.\n", debugstr_guid(tid_ids[tid]), hr);
+ return hr;
+ }
+
+ if (InterlockedCompareExchangePointer((void**)(typeinfos + tid), ti, NULL))
+ ITypeInfo_Release(ti);
+ }
+
+ *typeinfo = typeinfos[tid];
+ ITypeInfo_AddRef(typeinfos[tid]);
+ return S_OK;
+}
+
+static void release_typelib(void)
+{
+ unsigned i;
+
+ if (!typelib)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(typeinfos); i++)
+ if (typeinfos[i])
+ ITypeInfo_Release(typeinfos[i]);
+
+ ITypeLib_Release(typelib);
+}
+
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID lpv)
{
switch(reason)
@@ -371,6 +436,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID lpv)
COMSVCS_hInstance = hinst;
DisableThreadLibraryCalls(hinst);
break;
+ case DLL_PROCESS_DETACH:
+ release_typelib();
+ break;
}
return TRUE;
}
diff --git a/dlls/comsvcs/property.c b/dlls/comsvcs/property.c
index d1d03a03fe..0fc78e233f 100644
--- a/dlls/comsvcs/property.c
+++ b/dlls/comsvcs/property.c
@@ -82,31 +82,61 @@ static ULONG WINAPI group_manager_Release(ISharedPropertyGroupManager *iface)
static HRESULT WINAPI group_manager_GetTypeInfoCount(ISharedPropertyGroupManager *iface, UINT *info)
{
- FIXME("iface %p, info %p: stub.\n", iface, info);
- return E_NOTIMPL;
+ TRACE("iface %p, info %p.\n", iface, info);
+
+ if (!info)
+ return E_INVALIDARG;
+ *info = 1;
+ return S_OK;
}
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;
+ HRESULT hr;
+
+ TRACE("iface %p, index %u, lcid %u, info %p.\n", iface, index, lcid, info);
+
+ if (index)
+ return DISP_E_BADINDEX;
+
+ hr = get_typeinfo(ISharedPropertyGroupManager_tid, info);
+ if (SUCCEEDED(hr))
+ ITypeInfo_AddRef(*info);
+ return hr;
}
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",
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("iface %p, riid %s, names %p, count %u, lcid %u, dispid %p.\n",
iface, debugstr_guid(riid), names, count, lcid, dispid);
- return E_NOTIMPL;
+ hr = get_typeinfo(ISharedPropertyGroupManager_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, dispid);
+ ITypeInfo_Release(typeinfo);
+ }
+
+ return hr;
}
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",
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("iface %p, member %u, riid %s, lcid %u, flags %x, params %p, result %p, except %p, argerr %p.\n",
iface, member, debugstr_guid(riid), lcid, flags, params, result, except, argerr);
- return E_NOTIMPL;
+
+ hr = get_typeinfo(ISharedPropertyGroupManager_tid, &typeinfo);
+ if (SUCCEEDED(hr))
+ hr = ITypeInfo_Invoke(typeinfo, iface, member, flags, params, result, except, argerr);
+ return hr;
}
static HRESULT WINAPI group_manager_CreatePropertyGroup(ISharedPropertyGroupManager *iface, BSTR name, LONG *isolation,
diff --git a/dlls/comsvcs/tests/property.c b/dlls/comsvcs/tests/property.c
index 45375028d8..6d78cd39cd 100644
--- a/dlls/comsvcs/tests/property.c
+++ b/dlls/comsvcs/tests/property.c
@@ -60,6 +60,54 @@ static const IUnknownVtbl outer_vtbl =
static IUnknown test_outer = {&outer_vtbl};
+struct test_name_id
+{
+ const WCHAR *name;
+ DISPID id;
+};
+
+#define TEST_TYPEINFO(dispatch,test_name_ids,id_count,riid) _test_typeinfo(dispatch, test_name_ids, id_count, riid, __LINE__)
+static void _test_typeinfo(IDispatch *dispatch, struct test_name_id *test_name_ids, UINT id_count, REFIID riid, int line)
+{
+ static const LCID english = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ ITypeInfo *typeinfo;
+ TYPEATTR *typeattr;
+ DISPID dispid;
+ UINT count;
+ BSTR names;
+ HRESULT hr;
+ int i;
+
+ hr = IDispatch_GetTypeInfoCount(dispatch, NULL);
+ ok_(__FILE__,line)(hr == E_INVALIDARG, "GetTypeInfoCount got hr %#x.\n", hr);
+
+ count = 0xdeadbeef;
+ hr = IDispatch_GetTypeInfoCount(dispatch, &count);
+ ok_(__FILE__,line)(hr == S_OK, "GetTypeInfoCount got hr %#x.\n", hr);
+ ok_(__FILE__,line)(count == 1, "Got unexpected count: %d.\n", count);
+
+ hr = IDispatch_GetTypeInfo(dispatch, 1, english, &typeinfo);
+ ok_(__FILE__,line)(hr == DISP_E_BADINDEX, "GetTypeInfo got hr %#x.\n", hr);
+
+ hr = IDispatch_GetTypeInfo(dispatch, 0, english, &typeinfo);
+ ok_(__FILE__,line)(hr == S_OK, "GetTypeInfo failed %#x.\n", hr);
+ hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
+ ok_(__FILE__,line)(hr == S_OK, "GetTypeAttr got hr %#x.\n", hr);
+ ok_(__FILE__,line)(IsEqualGUID(&typeattr->guid, riid),
+ "Got unexpected type guid: %s.\n", wine_dbgstr_guid(&typeattr->guid));
+ ITypeInfo_Release(typeinfo);
+
+ for (i = 0; i < id_count; i++)
+ {
+ names = SysAllocString(test_name_ids[i].name);
+ dispid = 0xdeadbeef;
+ hr = IDispatch_GetIDsOfNames(dispatch, &IID_NULL, &names, 1, english, &dispid);
+ SysFreeString(names);
+ ok_(__FILE__,line)(hr == S_OK, "tests[%d] got hr %#x.\n", i, hr);
+ ok_(__FILE__,line)(dispid == test_name_ids[i].id, "tests[%d] got wrong dispid %x.\n", i, dispid);
+ }
+}
+
static void test_interfaces(void)
{
ISharedPropertyGroupManager *manager, *manager1;
@@ -67,6 +115,12 @@ static void test_interfaces(void)
IDispatch *dispatch;
IUnknown *unk;
HRESULT hr;
+ struct test_name_id test_name_ids[] =
+ {
+ {L"CreatePropertyGroup", 0x1},
+ {L"Group", 0x2},
+ {L"_NewEnum", 0xfffffffc},
+ };
hr = CoCreateInstance(&CLSID_SharedPropertyGroupManager, &test_outer, CLSCTX_INPROC_SERVER,
&IID_ISharedPropertyGroupManager, (void **)&manager);
@@ -103,6 +157,8 @@ static void test_interfaces(void)
refcount = get_refcount(manager);
ok(refcount == expected_refcount, "Got refcount: %d, expected %d.\n", refcount, expected_refcount);
+ TEST_TYPEINFO(dispatch, test_name_ids, ARRAY_SIZE(test_name_ids), &IID_ISharedPropertyGroupManager);
+
IDispatch_Release(dispatch);
IUnknown_Release(unk);
ISharedPropertyGroupManager_Release(manager);
--
2.28.0
2
1
17 Aug '20
Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
dlls/ntdll/unix/system.c | 14 +++++++++++++-
include/winnt.h | 6 ++++++
include/winternl.h | 6 ++++++
programs/wineboot/wineboot.c | 5 +++++
4 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index 3148f23df36..9d82a6774c6 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -190,6 +190,7 @@ __ASM_GLOBAL_FUNC( do_cpuid,
"pushl %ebx\n\t"
"movl 12(%esp),%eax\n\t"
"movl 16(%esp),%esi\n\t"
+ "xorl %ecx,%ecx\n\t"
"cpuid\n\t"
"movl %eax,(%esi)\n\t"
"movl %ebx,4(%esi)\n\t"
@@ -202,6 +203,7 @@ __ASM_GLOBAL_FUNC( do_cpuid,
__ASM_GLOBAL_FUNC( do_cpuid,
"pushq %rbx\n\t"
"movl %edi,%eax\n\t"
+ "xorl %ecx,%ecx\n\t"
"cpuid\n\t"
"movl %eax,(%rsi)\n\t"
"movl %ebx,4(%rsi)\n\t"
@@ -277,7 +279,7 @@ static inline BOOL have_sse_daz_mode(void)
static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
{
- unsigned int regs[4], regs2[4];
+ unsigned int regs[4], regs2[4], regs3[4];
#if defined(__i386__)
info->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
@@ -308,11 +310,21 @@ static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
if (regs2[3] & (1 << 25)) info->FeatureSet |= CPU_FEATURE_SSE;
if (regs2[3] & (1 << 26)) info->FeatureSet |= CPU_FEATURE_SSE2;
if (regs2[2] & (1 << 0 )) info->FeatureSet |= CPU_FEATURE_SSE3;
+ if (regs2[2] & (1 << 9 )) info->FeatureSet |= CPU_FEATURE_SSSE3;
if (regs2[2] & (1 << 13)) info->FeatureSet |= CPU_FEATURE_CX128;
+ if (regs2[2] & (1 << 19)) info->FeatureSet |= CPU_FEATURE_SSE41;
+ if (regs2[2] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_SSE42;
if (regs2[2] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_XSAVE;
+ if (regs2[2] & (1 << 28)) info->FeatureSet |= CPU_FEATURE_AVX;
if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
info->FeatureSet |= CPU_FEATURE_DAZ;
+ if (regs[0] >= 0x00000007)
+ {
+ do_cpuid( 0x00000007, regs3 ); /* get extended features */
+ if (regs3[1] & (1 << 5)) info->FeatureSet |= CPU_FEATURE_AVX2;
+ }
+
if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
{
info->Level = (regs2[0] >> 8) & 0xf; /* family */
diff --git a/include/winnt.h b/include/winnt.h
index 6aef97595dd..ac89ebc5ef7 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -928,6 +928,12 @@ typedef enum _HEAP_INFORMATION_CLASS {
#define PF_RDPID_INSTRUCTION_AVAILABLE 33
#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34
#define PF_MONITORX_INSTRUCTION_AVAILABLE 35
+#define PF_SSSE3_INSTRUCTIONS_AVAILABLE 36
+#define PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37
+#define PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38
+#define PF_AVX_INSTRUCTIONS_AVAILABLE 39
+#define PF_AVX2_INSTRUCTIONS_AVAILABLE 40
+#define PF_AVX512F_INSTRUCTIONS_AVAILABLE 41
/* Execution state flags */
diff --git a/include/winternl.h b/include/winternl.h
index 8efdaf31193..6c809193977 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1681,6 +1681,12 @@ typedef struct _SYSTEM_CPU_INFORMATION {
#define CPU_FEATURE_NX 0x20000000 /* Data execution prevention */
/* FIXME: following values are made up, actual flags are unknown */
+#define CPU_FEATURE_SSSE3 0x00008000 /* SSSE3 instructions */
+#define CPU_FEATURE_SSE41 0x01000000 /* SSE41 instructions */
+#define CPU_FEATURE_SSE42 0x02000000 /* SSE42 instructions */
+#define CPU_FEATURE_AVX 0x40000000 /* AVX instructions */
+#define CPU_FEATURE_AVX2 0x80000000 /* AVX2 instructions */
+
#define CPU_FEATURE_PAE 0x00200000
#define CPU_FEATURE_DAZ 0x00400000
#define CPU_FEATURE_ARM_VFP_32 0x00000001
diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c
index 21be0f55fb0..902f6af042e 100644
--- a/programs/wineboot/wineboot.c
+++ b/programs/wineboot/wineboot.c
@@ -248,6 +248,7 @@ static void create_user_shared_data(void)
features[PF_PAE_ENABLED] = !!(sci.FeatureSet & CPU_FEATURE_PAE);
features[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_SSE2);
features[PF_SSE3_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_SSE3);
+ features[PF_SSSE3_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_SSSE3);
features[PF_XSAVE_ENABLED] = !!(sci.FeatureSet & CPU_FEATURE_XSAVE);
features[PF_COMPARE_EXCHANGE128] = !!(sci.FeatureSet & CPU_FEATURE_CX128);
features[PF_SSE_DAZ_MODE_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_DAZ);
@@ -256,6 +257,10 @@ static void create_user_shared_data(void)
features[PF_VIRT_FIRMWARE_ENABLED] = !!(sci.FeatureSet & CPU_FEATURE_VIRT);
features[PF_RDWRFSGSBASE_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_RDFS);
features[PF_FASTFAIL_AVAILABLE] = TRUE;
+ features[PF_SSE4_1_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_SSE41);
+ features[PF_SSE4_2_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_SSE42);
+ features[PF_AVX_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_AVX);
+ features[PF_AVX2_INSTRUCTIONS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_AVX2);
break;
case PROCESSOR_ARCHITECTURE_ARM:
features[PF_ARM_VFP_32_REGISTERS_AVAILABLE] = !!(sci.FeatureSet & CPU_FEATURE_ARM_VFP_32);
--
2.26.2
1
0
17 Aug '20
Contains contributions from Mark Harmstone and Zhiyi Zhang.
Some devices, especially USB devices, have very irregular timing or
very long periods. Some Windows applications (The Witcher 3) are built
to expect regular, short period times, and so would underrun when the
device timing didn't match their expectations. This patch decouples
the Windows-side timing from the OS-side timing so we can meet those
applications' requirements.
Signed-off-by: Andrew Eikum <aeikum(a)codeweavers.com>
---
This patch has been in wine-staging and Proton for years. Finally
squashing down the fixes and submitting it upstream.
dlls/winepulse.drv/mmdevdrv.c | 617 ++++++++++++++++------------------
1 file changed, 281 insertions(+), 336 deletions(-)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index 23c34a50f66..e34c5ea5916 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -172,13 +172,16 @@ struct ACImpl {
EDataFlow dataflow;
DWORD flags;
AUDCLNT_SHAREMODE share;
- HANDLE event;
+ HANDLE event, timer;
INT32 locked;
- UINT32 bufsize_frames, bufsize_bytes, capture_period, pad, started, peek_ofs, wri_offs_bytes, lcl_offs_bytes;
- UINT32 tmp_buffer_bytes, held_bytes, peek_len, peek_buffer_len;
+ UINT32 bufsize_frames, real_bufsize_bytes, period_bytes;
+ UINT32 started, peek_ofs, read_offs_bytes, lcl_offs_bytes, pa_offs_bytes;
+ UINT32 tmp_buffer_bytes, held_bytes, peek_len, peek_buffer_len, pa_held_bytes;
BYTE *local_buffer, *tmp_buffer, *peek_buffer;
void *locked_ptr;
+ BOOL please_quit, just_started, just_underran;
+ pa_usec_t last_time, mmdev_period_usec;
pa_stream *stream;
pa_sample_spec ss;
@@ -709,18 +712,7 @@ static void silence_buffer(pa_sample_format_t format, BYTE *buffer, UINT32 bytes
memset(buffer, format == PA_SAMPLE_U8 ? 0x80 : 0, bytes);
}
-static void pulse_free_noop(void *buf)
-{
-}
-
-enum write_buffer_flags
-{
- WINEPULSE_WRITE_NOFREE = 0x01,
- WINEPULSE_WRITE_SILENT = 0x02
-};
-
-static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes,
- enum write_buffer_flags flags)
+static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes)
{
float vol[PA_CHANNELS_MAX];
BOOL adjust = FALSE;
@@ -728,7 +720,7 @@ static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes,
BYTE *end;
if (!bytes) return 0;
- if (This->session->mute || (flags & WINEPULSE_WRITE_SILENT))
+ if (This->session->mute)
{
silence_buffer(This->ss.format, buffer, bytes);
goto write;
@@ -855,9 +847,7 @@ static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes,
}
write:
- return pa_stream_write(This->stream, buffer, bytes,
- (flags & WINEPULSE_WRITE_NOFREE) ? pulse_free_noop : NULL,
- 0, PA_SEEK_RELATIVE);
+ return pa_stream_write(This->stream, buffer, bytes, NULL, 0, PA_SEEK_RELATIVE);
}
static void dump_attr(const pa_buffer_attr *attr) {
@@ -880,147 +870,129 @@ static void pulse_attr_update(pa_stream *s, void *user) {
dump_attr(attr);
}
-/* Here's the buffer setup:
- *
- * vvvvvvvv sent to HW already
- * vvvvvvvv in Pulse buffer but rewindable
- * [dddddddddddddddd] Pulse buffer
- * [dddddddddddddddd--------] mmdevapi buffer
- * ^^^^^^^^^^^^^^^^ pad
- * ^ lcl_offs_bytes
- * ^^^^^^^^^ held_bytes
- * ^ wri_offs_bytes
- *
- * GetCurrentPadding is pad
- *
- * During pulse_wr_callback, we decrement pad, fill Pulse buffer, and move
- * lcl_offs forward
- *
- * During Stop, we flush the Pulse buffer
- */
-static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
+static void pulse_write(ACImpl *This)
{
- ACImpl *This = userdata;
- UINT32 oldpad = This->pad;
+ /* write as much data to PA as we can */
+ UINT32 to_write;
+ BYTE *buf = This->local_buffer + This->pa_offs_bytes;
+ UINT32 bytes = pa_stream_writable_size(This->stream);
- if(This->local_buffer){
- UINT32 to_write;
- BYTE *buf = This->local_buffer + This->lcl_offs_bytes;
-
- if(This->pad > bytes){
- This->clock_written += bytes;
- This->pad -= bytes;
- }else{
- This->clock_written += This->pad;
- This->pad = 0;
+ if(This->just_underran){
+ /* prebuffer with silence if needed */
+ if(This->pa_held_bytes < bytes){
+ to_write = bytes - This->pa_held_bytes;
+ TRACE("prebuffering %u frames of silence\n",
+ (int)(to_write / pa_frame_size(&This->ss)));
+ buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, to_write);
+ pa_stream_write(This->stream, buf, to_write, NULL, 0, PA_SEEK_RELATIVE);
+ HeapFree(GetProcessHeap(), 0, buf);
}
- bytes = min(bytes, This->held_bytes);
-
- if(This->lcl_offs_bytes + bytes > This->bufsize_bytes){
- to_write = This->bufsize_bytes - This->lcl_offs_bytes;
- TRACE("writing small chunk of %u bytes\n", to_write);
- write_buffer(This, buf, to_write, 0);
- This->held_bytes -= to_write;
- to_write = bytes - to_write;
- This->lcl_offs_bytes = 0;
- buf = This->local_buffer;
- }else
- to_write = bytes;
-
- TRACE("writing main chunk of %u bytes\n", to_write);
- write_buffer(This, buf, to_write, 0);
- This->lcl_offs_bytes += to_write;
- This->lcl_offs_bytes %= This->bufsize_bytes;
- This->held_bytes -= to_write;
- }else{
- if (bytes < This->bufsize_bytes)
- This->pad = This->bufsize_bytes - bytes;
- else
- This->pad = 0;
-
- if (oldpad == This->pad)
- return;
-
- assert(oldpad > This->pad);
-
- This->clock_written += oldpad - This->pad;
- TRACE("New pad: %zu (-%zu)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
+ This->just_underran = FALSE;
}
- if (This->event)
- SetEvent(This->event);
+ buf = This->local_buffer + This->pa_offs_bytes;
+ TRACE("held: %u, avail: %u\n",
+ This->pa_held_bytes, bytes);
+ bytes = min(This->pa_held_bytes, bytes);
+
+ if(This->pa_offs_bytes + bytes > This->real_bufsize_bytes){
+ to_write = This->real_bufsize_bytes - This->pa_offs_bytes;
+ TRACE("writing small chunk of %u bytes\n", to_write);
+ write_buffer(This, buf, to_write);
+ This->pa_held_bytes -= to_write;
+ to_write = bytes - to_write;
+ This->pa_offs_bytes = 0;
+ buf = This->local_buffer;
+ }else
+ to_write = bytes;
+
+ TRACE("writing main chunk of %u bytes\n", to_write);
+ write_buffer(This, buf, to_write);
+ This->pa_offs_bytes += to_write;
+ This->pa_offs_bytes %= This->real_bufsize_bytes;
+ This->pa_held_bytes -= to_write;
}
static void pulse_underflow_callback(pa_stream *s, void *userdata)
-{
- WARN("Underflow\n");
-}
-
-/* Latency is periodically updated even when nothing is played,
- * because of PA_STREAM_AUTO_TIMING_UPDATE so use it as timer
- *
- * Perfect for passing all tests :)
- */
-static void pulse_latency_callback(pa_stream *s, void *userdata)
{
ACImpl *This = userdata;
- if (!This->pad && This->event)
- SetEvent(This->event);
+ WARN("%p: Underflow\n", userdata);
+ This->just_underran = TRUE;
+ /* re-sync */
+ This->pa_offs_bytes = This->lcl_offs_bytes;
+ This->pa_held_bytes = This->held_bytes;
}
static void pulse_started_callback(pa_stream *s, void *userdata)
{
- TRACE("(Re)started playing\n");
+ TRACE("%p: (Re)started playing\n", userdata);
}
-static void pulse_rd_loop(ACImpl *This, size_t bytes)
+static void pulse_read(ACImpl *This)
{
- while (bytes >= This->capture_period) {
- ACPacket *p, *next;
- LARGE_INTEGER stamp, freq;
- BYTE *dst, *src;
- size_t src_len, copy, rem = This->capture_period;
- if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
- p = (ACPacket*)list_head(&This->packet_filled_head);
- if (!p->discont) {
- next = (ACPacket*)p->entry.next;
- next->discont = 1;
- } else
- p = (ACPacket*)list_tail(&This->packet_filled_head);
- assert(This->pad == This->bufsize_bytes);
- } else {
- assert(This->pad < This->bufsize_bytes);
- This->pad += This->capture_period;
- assert(This->pad <= This->bufsize_bytes);
+ size_t bytes = pa_stream_readable_size(This->stream);
+
+ TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(This->stream)->fragsize);
+
+ bytes += This->peek_len - This->peek_ofs;
+
+ while (bytes >= This->period_bytes) {
+ BYTE *dst = NULL, *src;
+ size_t src_len, copy, rem = This->period_bytes;
+
+ if (This->started) {
+ LARGE_INTEGER stamp, freq;
+ ACPacket *p, *next;
+
+ if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
+ p = (ACPacket*)list_head(&This->packet_filled_head);
+ if (!p) return;
+ if (!p->discont) {
+ next = (ACPacket*)p->entry.next;
+ next->discont = 1;
+ } else
+ p = (ACPacket*)list_tail(&This->packet_filled_head);
+ } else {
+ This->held_bytes += This->period_bytes;
+ }
+ QueryPerformanceCounter(&stamp);
+ QueryPerformanceFrequency(&freq);
+ p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
+ p->discont = 0;
+ list_remove(&p->entry);
+ list_add_tail(&This->packet_filled_head, &p->entry);
+
+ dst = p->data;
}
- QueryPerformanceCounter(&stamp);
- QueryPerformanceFrequency(&freq);
- p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
- p->discont = 0;
- list_remove(&p->entry);
- list_add_tail(&This->packet_filled_head, &p->entry);
- dst = p->data;
while (rem) {
if (This->peek_len) {
copy = min(rem, This->peek_len - This->peek_ofs);
- memcpy(dst, This->peek_buffer + This->peek_ofs, copy);
+ if (dst) {
+ memcpy(dst, This->peek_buffer + This->peek_ofs, copy);
+ dst += copy;
+ }
rem -= copy;
- dst += copy;
This->peek_ofs += copy;
if(This->peek_len == This->peek_ofs)
- This->peek_len = 0;
- } else {
- pa_stream_peek(This->stream, (const void**)&src, &src_len);
+ This->peek_len = This->peek_ofs = 0;
+
+ } else if (pa_stream_peek(This->stream, (const void**)&src, &src_len) == 0 && src_len) {
copy = min(rem, src_len);
- memcpy(dst, src, rem);
+ if (dst) {
+ if(src)
+ memcpy(dst, src, copy);
+ else
+ silence_buffer(This->ss.format, dst, copy);
+
+ dst += copy;
+ }
- dst += copy;
rem -= copy;
if (copy < src_len) {
@@ -1030,7 +1002,11 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
This->peek_buffer_len = src_len;
}
- memcpy(This->peek_buffer, src + copy, src_len - copy);
+ if(src)
+ memcpy(This->peek_buffer, src + copy, src_len - copy);
+ else
+ silence_buffer(This->ss.format, This->peek_buffer, src_len - copy);
+
This->peek_len = src_len - copy;
This->peek_ofs = 0;
}
@@ -1039,56 +1015,100 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
}
}
- bytes -= This->capture_period;
+ bytes -= This->period_bytes;
}
}
-static void pulse_rd_drop(ACImpl *This, size_t bytes)
+static DWORD WINAPI pulse_timer_cb(void *user)
{
- while (bytes >= This->capture_period) {
- size_t src_len, copy, rem = This->capture_period;
- while (rem) {
- const void *src;
- pa_stream_peek(This->stream, &src, &src_len);
- assert(src_len);
- assert(This->peek_ofs < src_len);
- src_len -= This->peek_ofs;
- assert(src_len <= bytes);
-
- copy = rem;
- if (copy > src_len)
- copy = src_len;
-
- src_len -= copy;
- rem -= copy;
-
- if (!src_len) {
- This->peek_ofs = 0;
- pa_stream_drop(This->stream);
- } else
- This->peek_ofs += copy;
- bytes -= copy;
+ DWORD delay;
+ UINT32 adv_bytes;
+ ACImpl *This = user;
+ int success;
+ pa_operation *o;
+
+ pthread_mutex_lock(&pulse_lock);
+ delay = This->mmdev_period_usec / 1000;
+ pa_stream_get_time(This->stream, &This->last_time);
+ pthread_mutex_unlock(&pulse_lock);
+
+ while(!This->please_quit){
+ pa_usec_t now, adv_usec = 0;
+ int err;
+
+ Sleep(delay);
+
+ pthread_mutex_lock(&pulse_lock);
+
+ delay = This->mmdev_period_usec / 1000;
+
+ o = pa_stream_update_timing_info(This->stream, pulse_op_cb, &success);
+ if (o)
+ {
+ while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
+ pa_operation_unref(o);
}
- }
-}
+ err = pa_stream_get_time(This->stream, &now);
+ if(err == 0){
+ TRACE("got now: %s, last time: %s\n", wine_dbgstr_longlong(now), wine_dbgstr_longlong(This->last_time));
+ if(This->started && (This->dataflow == eCapture || This->held_bytes)){
+ if(This->just_underran){
+ This->last_time = now;
+ This->just_started = TRUE;
+ }
-static void pulse_rd_callback(pa_stream *s, size_t bytes, void *userdata)
-{
- ACImpl *This = userdata;
+ if(This->just_started){
+ /* let it play out a period to absorb some latency and get accurate timing */
+ pa_usec_t diff = now - This->last_time;
+
+ if(diff > This->mmdev_period_usec){
+ This->just_started = FALSE;
+ This->last_time = now;
+ }
+ }else{
+ INT32 adjust = This->last_time + This->mmdev_period_usec - now;
- TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize);
- assert(bytes >= This->peek_ofs);
- bytes -= This->peek_ofs;
- if (bytes < This->capture_period)
- return;
+ adv_usec = now - This->last_time;
- if (This->started)
- pulse_rd_loop(This, bytes);
- else
- pulse_rd_drop(This, bytes);
+ if(adjust > ((INT32)(This->mmdev_period_usec / 2)))
+ adjust = This->mmdev_period_usec / 2;
+ else if(adjust < -((INT32)(This->mmdev_period_usec / 2)))
+ adjust = -1 * This->mmdev_period_usec / 2;
+
+ delay = (This->mmdev_period_usec + adjust) / 1000;
+
+ This->last_time += This->mmdev_period_usec;
+ }
+
+ if(This->dataflow == eRender){
+ pulse_write(This);
+
+ /* regardless of what PA does, advance one period */
+ adv_bytes = min(This->period_bytes, This->held_bytes);
+ This->lcl_offs_bytes += adv_bytes;
+ This->lcl_offs_bytes %= This->real_bufsize_bytes;
+ This->held_bytes -= adv_bytes;
+ }else if(This->dataflow == eCapture){
+ pulse_read(This);
+ }
+ }else{
+ This->last_time = now;
+ delay = This->mmdev_period_usec / 1000;
+ }
+ }
+
+ if (This->event)
+ SetEvent(This->event);
+
+ TRACE("%p after update, adv usec: %d, held: %u, delay: %u\n",
+ This, (int)adv_usec,
+ (int)(This->held_bytes/ pa_frame_size(&This->ss)), delay);
+
+ pthread_mutex_unlock(&pulse_lock);
+ }
- if (This->event)
- SetEvent(This->event);
+ return 0;
}
static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
@@ -1117,15 +1137,16 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
/* PulseAudio will fill in correct values */
attr.minreq = attr.fragsize = period_bytes;
- attr.maxlength = attr.tlength = This->bufsize_bytes;
+ attr.tlength = period_bytes * 3;
+ attr.maxlength = This->bufsize_frames * pa_frame_size(&This->ss);
attr.prebuf = pa_frame_size(&This->ss);
dump_attr(&attr);
if (This->dataflow == eRender)
ret = pa_stream_connect_playback(This->stream, NULL, &attr,
- PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
+ PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY, NULL, NULL);
else
ret = pa_stream_connect_record(This->stream, NULL, &attr,
- PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS);
+ PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_ADJUST_LATENCY);
if (ret < 0) {
WARN("Returns %i\n", ret);
return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
@@ -1136,11 +1157,9 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
if (This->dataflow == eRender) {
- pa_stream_set_write_callback(This->stream, pulse_wr_callback, This);
pa_stream_set_underflow_callback(This->stream, pulse_underflow_callback, This);
pa_stream_set_started_callback(This->stream, pulse_started_callback, This);
- } else
- pa_stream_set_read_callback(This->stream, pulse_rd_callback, This);
+ }
return S_OK;
}
@@ -1275,6 +1294,11 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
TRACE("(%p) Refcount now %u\n", This, ref);
if (!ref) {
if (This->stream) {
+ if(This->timer){
+ This->please_quit = TRUE;
+ WaitForSingleObject(This->timer, INFINITE);
+ CloseHandle(This->timer);
+ }
pthread_mutex_lock(&pulse_lock);
if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) {
pa_stream_disconnect(This->stream);
@@ -1570,7 +1594,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
{
ACImpl *This = impl_from_IAudioClient(iface);
HRESULT hr = S_OK;
- UINT period_bytes;
+ UINT32 bufsize_bytes;
TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
@@ -1617,38 +1641,19 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
if (FAILED(hr))
goto exit;
- if (mode == AUDCLNT_SHAREMODE_SHARED) {
- REFERENCE_TIME def = pulse_def_period[This->dataflow == eCapture];
- REFERENCE_TIME min = pulse_min_period[This->dataflow == eCapture];
+ period = pulse_def_period[This->dataflow == eCapture];
+ if (duration < 3 * period)
+ duration = 3 * period;
- /* Switch to low latency mode if below 2 default periods,
- * which is 20 ms by default, this will increase the amount
- * of interrupts but allows very low latency. In dsound I
- * managed to get a total latency of ~8ms, which is well below
- * default
- */
- if (duration < 2 * def)
- period = min;
- else
- period = def;
- if (duration < 2 * period)
- duration = 2 * period;
+ This->period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
- /* Uh oh, really low latency requested.. */
- if (duration <= 2 * period)
- period /= 2;
- }
- period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
-
- if (duration < 20000000)
- This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
- else
- This->bufsize_frames = 2 * fmt->nSamplesPerSec;
- This->bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss);
+ This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
+ bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss);
+ This->mmdev_period_usec = period / 10;
This->share = mode;
This->flags = flags;
- hr = pulse_stream_connect(This, period_bytes);
+ hr = pulse_stream_connect(This, This->period_bytes);
if (SUCCEEDED(hr)) {
UINT32 unalign;
const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream);
@@ -1656,39 +1661,34 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
/* Update frames according to new size */
dump_attr(attr);
if (This->dataflow == eRender) {
- if (attr->tlength < This->bufsize_bytes) {
- TRACE("PulseAudio buffer too small (%u < %u), using tmp buffer\n", attr->tlength, This->bufsize_bytes);
-
- This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes);
- if(!This->local_buffer)
- hr = E_OUTOFMEMORY;
- }
+ This->real_bufsize_bytes = This->bufsize_frames * 2 * pa_frame_size(&This->ss);
+ This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->real_bufsize_bytes);
+ if(!This->local_buffer)
+ hr = E_OUTOFMEMORY;
} else {
UINT32 i, capture_packets;
- This->capture_period = period_bytes = attr->fragsize;
- if ((unalign = This->bufsize_bytes % period_bytes))
- This->bufsize_bytes += period_bytes - unalign;
- This->bufsize_frames = This->bufsize_bytes / pa_frame_size(&This->ss);
+ if ((unalign = bufsize_bytes % This->period_bytes))
+ bufsize_bytes += This->period_bytes - unalign;
+ This->bufsize_frames = bufsize_bytes / pa_frame_size(&This->ss);
+ This->real_bufsize_bytes = bufsize_bytes;
- capture_packets = This->bufsize_bytes / This->capture_period;
+ capture_packets = This->real_bufsize_bytes / This->period_bytes;
- This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes + capture_packets * sizeof(ACPacket));
+ This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->real_bufsize_bytes + capture_packets * sizeof(ACPacket));
if (!This->local_buffer)
hr = E_OUTOFMEMORY;
else {
- ACPacket *cur_packet = (ACPacket*)((char*)This->local_buffer + This->bufsize_bytes);
+ ACPacket *cur_packet = (ACPacket*)((char*)This->local_buffer + This->real_bufsize_bytes);
BYTE *data = This->local_buffer;
- silence_buffer(This->ss.format, This->local_buffer, This->bufsize_bytes);
+ silence_buffer(This->ss.format, This->local_buffer, This->real_bufsize_bytes);
list_init(&This->packet_free_head);
list_init(&This->packet_filled_head);
for (i = 0; i < capture_packets; ++i, ++cur_packet) {
list_add_tail(&This->packet_free_head, &cur_packet->entry);
cur_packet->data = data;
- data += This->capture_period;
+ data += This->period_bytes;
}
- assert(!This->capture_period || This->bufsize_bytes == This->capture_period * capture_packets);
- assert(!capture_packets || data - This->bufsize_bytes == This->local_buffer);
}
}
}
@@ -1753,12 +1753,12 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
attr = pa_stream_get_buffer_attr(This->stream);
if (This->dataflow == eRender){
lat = attr->minreq / pa_frame_size(&This->ss);
- lat += pulse_def_period[0];
}else
lat = attr->fragsize / pa_frame_size(&This->ss);
*latency = 10000000;
*latency *= lat;
*latency /= This->ss.rate;
+ *latency += pulse_def_period[0];
pthread_mutex_unlock(&pulse_lock);
TRACE("Latency: %u ms\n", (DWORD)(*latency / 10000));
return S_OK;
@@ -1766,7 +1766,7 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
static void ACImpl_GetRenderPad(ACImpl *This, UINT32 *out)
{
- *out = This->pad / pa_frame_size(&This->ss);
+ *out = This->held_bytes / pa_frame_size(&This->ss);
}
static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out)
@@ -1778,7 +1778,7 @@ static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out)
list_remove(&packet->entry);
}
if (out)
- *out = This->pad / pa_frame_size(&This->ss);
+ *out = This->held_bytes / pa_frame_size(&This->ss);
}
static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
@@ -2024,6 +2024,8 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
return AUDCLNT_E_NOT_STOPPED;
}
+ pulse_write(This);
+
if (pa_stream_is_corked(This->stream)) {
o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success);
if (o) {
@@ -2038,8 +2040,10 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
if (SUCCEEDED(hr)) {
This->started = TRUE;
- if (This->dataflow == eRender && This->event)
- pa_stream_set_latency_update_callback(This->stream, pulse_latency_callback, This);
+ This->just_started = TRUE;
+
+ if(!This->timer)
+ This->timer = CreateThread(NULL, 0, pulse_timer_cb, This, 0, NULL);
}
pthread_mutex_unlock(&pulse_lock);
return hr;
@@ -2111,7 +2115,7 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
if (This->dataflow == eRender) {
/* If there is still data in the render buffer it needs to be removed from the server */
int success = 0;
- if (This->pad) {
+ if (This->held_bytes) {
pa_operation *o = pa_stream_flush(This->stream, pulse_op_cb, &success);
if (o) {
while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
@@ -2119,14 +2123,14 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
pa_operation_unref(o);
}
}
- if (success || !This->pad){
- This->clock_lastpos = This->clock_written = This->pad = 0;
- This->wri_offs_bytes = This->lcl_offs_bytes = This->held_bytes = 0;
+ if (success || !This->held_bytes){
+ This->clock_lastpos = This->clock_written = 0;
+ This->pa_offs_bytes = This->lcl_offs_bytes = This->held_bytes = This->pa_held_bytes = 0;
}
} else {
ACPacket *p;
- This->clock_written += This->pad;
- This->pad = 0;
+ This->clock_written += This->held_bytes;
+ This->held_bytes = 0;
if ((p = This->locked_ptr)) {
This->locked_ptr = NULL;
@@ -2292,10 +2296,9 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
UINT32 frames, BYTE **data)
{
ACImpl *This = impl_from_IAudioRenderClient(iface);
- size_t avail, req, bytes = frames * pa_frame_size(&This->ss);
- UINT32 pad;
+ size_t bytes = frames * pa_frame_size(&This->ss);
HRESULT hr = S_OK;
- int ret = -1;
+ UINT32 wri_offs_bytes;
TRACE("(%p)->(%u, %p)\n", This, frames, data);
@@ -2314,37 +2317,19 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
return S_OK;
}
- ACImpl_GetRenderPad(This, &pad);
- avail = This->bufsize_frames - pad;
- if (avail < frames || bytes > This->bufsize_bytes) {
+ if(This->held_bytes / pa_frame_size(&This->ss) + frames > This->bufsize_frames){
pthread_mutex_unlock(&pulse_lock);
- WARN("Wanted to write %u, but only %zu available\n", frames, avail);
return AUDCLNT_E_BUFFER_TOO_LARGE;
}
- if(This->local_buffer){
- if(This->wri_offs_bytes + bytes > This->bufsize_bytes){
- alloc_tmp_buffer(This, bytes);
- *data = This->tmp_buffer;
- This->locked = -frames;
- }else{
- *data = This->local_buffer + This->wri_offs_bytes;
- This->locked = frames;
- }
+ wri_offs_bytes = (This->lcl_offs_bytes + This->held_bytes) % This->real_bufsize_bytes;
+ if(wri_offs_bytes + bytes > This->real_bufsize_bytes){
+ alloc_tmp_buffer(This, bytes);
+ *data = This->tmp_buffer;
+ This->locked = -bytes;
}else{
- req = bytes;
- ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req);
- if (ret < 0 || req < bytes) {
- FIXME("%p Not using pulse locked data: %i %zu/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames);
- if (ret >= 0)
- pa_stream_cancel_write(This->stream);
- alloc_tmp_buffer(This, bytes);
- *data = This->tmp_buffer;
- This->locked_ptr = NULL;
- } else
- *data = This->locked_ptr;
-
- This->locked = frames;
+ *data = This->local_buffer + wri_offs_bytes;
+ This->locked = bytes;
}
silence_buffer(This->ss.format, *data, bytes);
@@ -2356,12 +2341,13 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
static void pulse_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
{
- UINT32 chunk_bytes = This->bufsize_bytes - This->wri_offs_bytes;
+ UINT32 wri_offs_bytes = (This->lcl_offs_bytes + This->held_bytes) % This->real_bufsize_bytes;
+ UINT32 chunk_bytes = This->real_bufsize_bytes - wri_offs_bytes;
if(written_bytes <= chunk_bytes){
- memcpy(This->local_buffer + This->wri_offs_bytes, buffer, written_bytes);
+ memcpy(This->local_buffer + wri_offs_bytes, buffer, written_bytes);
}else{
- memcpy(This->local_buffer + This->wri_offs_bytes, buffer, chunk_bytes);
+ memcpy(This->local_buffer + wri_offs_bytes, buffer, chunk_bytes);
memcpy(This->local_buffer, buffer + chunk_bytes,
written_bytes - chunk_bytes);
}
@@ -2372,88 +2358,47 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
{
ACImpl *This = impl_from_IAudioRenderClient(iface);
UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
+ BYTE *buffer;
TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
pthread_mutex_lock(&pulse_lock);
if (!This->locked || !written_frames) {
- if (This->locked_ptr)
- pa_stream_cancel_write(This->stream);
This->locked = 0;
- This->locked_ptr = NULL;
pthread_mutex_unlock(&pulse_lock);
return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
}
- if (This->locked < written_frames) {
+ if(written_frames * pa_frame_size(&This->ss) > (This->locked >= 0 ? This->locked : -This->locked)){
pthread_mutex_unlock(&pulse_lock);
return AUDCLNT_E_INVALID_SIZE;
}
- if(This->local_buffer){
- BYTE *buffer;
-
- if(This->locked >= 0)
- buffer = This->local_buffer + This->wri_offs_bytes;
- else
- buffer = This->tmp_buffer;
-
- if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
- silence_buffer(This->ss.format, buffer, written_bytes);
-
- if(This->locked < 0)
- pulse_wrap_buffer(This, buffer, written_bytes);
-
- This->wri_offs_bytes += written_bytes;
- This->wri_offs_bytes %= This->bufsize_bytes;
-
- This->pad += written_bytes;
- This->held_bytes += written_bytes;
-
- if(This->held_bytes == This->pad){
- int e;
- UINT32 to_write = min(This->attr.tlength, written_bytes);
-
- /* nothing in PA, so send data immediately */
-
- TRACE("pre-writing %u bytes\n", to_write);
-
- e = write_buffer(This, buffer, to_write, 0);
- if(e)
- ERR("pa_stream_write failed: 0x%x\n", e);
-
- This->lcl_offs_bytes += to_write;
- This->lcl_offs_bytes %= This->bufsize_bytes;
- This->held_bytes -= to_write;
- }
-
- }else{
- enum write_buffer_flags wr_flags = 0;
-
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT) wr_flags |= WINEPULSE_WRITE_SILENT;
- if (!This->locked_ptr) wr_flags |= WINEPULSE_WRITE_NOFREE;
-
- write_buffer(This, This->locked_ptr ? This->locked_ptr : This->tmp_buffer, written_bytes, wr_flags);
- This->pad += written_bytes;
- }
-
- if (!pa_stream_is_corked(This->stream)) {
- int success;
- pa_operation *o;
- o = pa_stream_trigger(This->stream, pulse_op_cb, &success);
- if (o) {
- while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
- pthread_cond_wait(&pulse_cond, &pulse_lock);
- pa_operation_unref(o);
- }
+ if(This->locked >= 0)
+ buffer = This->local_buffer + (This->lcl_offs_bytes + This->held_bytes) % This->real_bufsize_bytes;
+ else
+ buffer = This->tmp_buffer;
+
+ if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
+ silence_buffer(This->ss.format, buffer, written_bytes);
+
+ if(This->locked < 0)
+ pulse_wrap_buffer(This, buffer, written_bytes);
+
+ This->held_bytes += written_bytes;
+ This->pa_held_bytes += written_bytes;
+ if(This->pa_held_bytes > This->real_bufsize_bytes){
+ This->pa_offs_bytes += This->pa_held_bytes - This->real_bufsize_bytes;
+ This->pa_offs_bytes %= This->real_bufsize_bytes;
+ This->pa_held_bytes = This->real_bufsize_bytes;
}
-
+ This->clock_written += written_bytes;
This->locked = 0;
- This->locked_ptr = NULL;
- TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
- assert(This->pad <= This->bufsize_bytes);
+
+ TRACE("Released %u, held %zu\n", written_frames, This->held_bytes / pa_frame_size(&This->ss));
pthread_mutex_unlock(&pulse_lock);
+
return S_OK;
}
@@ -2530,13 +2475,13 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
ACImpl_GetCapturePad(This, NULL);
if ((packet = This->locked_ptr)) {
- *frames = This->capture_period / pa_frame_size(&This->ss);
+ *frames = This->period_bytes / pa_frame_size(&This->ss);
*flags = 0;
if (packet->discont)
*flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY;
if (devpos) {
if (packet->discont)
- *devpos = (This->clock_written + This->capture_period) / pa_frame_size(&This->ss);
+ *devpos = (This->clock_written + This->period_bytes) / pa_frame_size(&This->ss);
else
*devpos = This->clock_written / pa_frame_size(&This->ss);
}
@@ -2570,11 +2515,11 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
if (done) {
ACPacket *packet = This->locked_ptr;
This->locked_ptr = NULL;
- This->pad -= This->capture_period;
+ This->held_bytes -= This->period_bytes;
if (packet->discont)
- This->clock_written += 2 * This->capture_period;
+ This->clock_written += 2 * This->period_bytes;
else
- This->clock_written += This->capture_period;
+ This->clock_written += This->period_bytes;
list_add_tail(&This->packet_free_head, &packet->entry);
}
This->locked = 0;
@@ -2594,7 +2539,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
pthread_mutex_lock(&pulse_lock);
ACImpl_GetCapturePad(This, NULL);
if (This->locked_ptr)
- *frames = This->capture_period / pa_frame_size(&This->ss);
+ *frames = This->period_bytes / pa_frame_size(&This->ss);
else
*frames = 0;
pthread_mutex_unlock(&pulse_lock);
@@ -2686,7 +2631,7 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
return hr;
}
- *pos = This->clock_written;
+ *pos = This->clock_written - This->held_bytes;
if (This->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
*pos /= pa_frame_size(&This->ss);
--
2.28.0
1
0
Since some month I keep splitting/cleaning up/rebasing the PowerPC64le patchset from last year: [1]
The goal is to have a winelib base for Hangover [2] on PowerPC64 and there's also interest in having
winelib for crosscompiling [3].
[1] https://github.com/madscientist159/wine/commits/master
[2] https://github.com/AndreRH/hangover
[3] https://wiki.raptorcs.com/wiki/Porting/Wine
2
30
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
---
dlls/msvcrt/tests/string.c | 86 ++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index a4b1fb9d11..a08a76fc68 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -4295,6 +4295,91 @@ static void test___STRINGTOLD(void)
}
}
+static void test_SpecialCasing(void)
+{
+ int i;
+ wint_t ret, exp;
+ _locale_t locale;
+ struct test {
+ const char *lang;
+ wint_t ch;
+ wint_t exp;
+ };
+
+ struct test ucases[] = {
+ {"English", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
+ {"English", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+
+ {"Turkish", 'I', 'i'}, /* LATIN CAPITAL LETTER I */
+ {"Turkish", 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ };
+ struct test lcases[] = {
+ {"English", 'i', 'I'}, /* LATIN SMALL LETTER I */
+ {"English", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
+
+ {"Turkish", 'i', 'I'}, /* LATIN SMALL LETTER I */
+ {"Turkish", 0x0131}, /* LATIN SMALL LETTER DOTLESS I */
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ucases); i++) {
+ if (!setlocale(LC_ALL, ucases[i].lang)) {
+ win_skip("skipping special case tests for %s\n", ucases[i].lang);
+ continue;
+ }
+
+ ret = p_towlower(ucases[i].ch);
+ exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
+ ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(lcases); i++) {
+ if (!setlocale(LC_ALL, lcases[i].lang)) {
+ win_skip("skipping special case tests for %s\n", lcases[i].lang);
+ continue;
+ }
+
+ ret = p_towupper(lcases[i].ch);
+ exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
+ ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
+ }
+
+ setlocale(LC_ALL, "C");
+
+ if (!p__towlower_l || !p__towupper_l || !p__create_locale)
+ {
+ win_skip("_towlower_l/_towupper_l/_create_locale not available\n");
+ return;
+ }
+
+ /* test _towlower_l creating locale */
+ for (i = 0; i < ARRAY_SIZE(ucases); i++) {
+ if (!(locale = p__create_locale(LC_ALL, ucases[i].lang))) {
+ win_skip("locale %s not available. skipping\n", ucases[i].lang);
+ continue;
+ }
+
+ ret = p__towlower_l(ucases[i].ch, locale);
+ exp = ucases[i].exp ? ucases[i].exp : ucases[i].ch;
+ ok(ret == exp, "expected lowercase %x, got %x for locale %s\n", exp, ret, ucases[i].lang);
+
+ p__free_locale(locale);
+ }
+
+ /* test _towupper_l creating locale */
+ for (i = 0; i < ARRAY_SIZE(lcases); i++) {
+ if (!(locale = p__create_locale(LC_ALL, lcases[i].lang))) {
+ win_skip("locale %s not available. skipping\n", lcases[i].lang);
+ continue;
+ }
+
+ ret = p__towupper_l(lcases[i].ch, locale);
+ exp = lcases[i].exp ? lcases[i].exp : lcases[i].ch;
+ ok(ret == exp, "expected uppercase %x, got %x for locale %s\n", exp, ret, lcases[i].lang);
+
+ p__free_locale(locale);
+ }
+}
+
START_TEST(string)
{
char mem[100];
@@ -4446,4 +4531,5 @@ START_TEST(string)
test_iswdigit();
test_wcscmp();
test___STRINGTOLD();
+ test_SpecialCasing();
}
--
2.25.1
2
3
[PATCH] ole32: Add a check for hglobal pointer to GetHGlobalFromStream.
by Dmitry Timoshkov 17 Aug '20
by Dmitry Timoshkov 17 Aug '20
17 Aug '20
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/ole32/hglobalstream.c | 4 ++--
dlls/ole32/tests/hglobalstream.c | 6 ++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c
index 4590bb9c43..4cfedd66a1 100644
--- a/dlls/ole32/hglobalstream.c
+++ b/dlls/ole32/hglobalstream.c
@@ -664,10 +664,10 @@ HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
{
HGLOBALStreamImpl* pStream;
- if (pstm == NULL)
+ if (!pstm || !phglobal)
return E_INVALIDARG;
- pStream = (HGLOBALStreamImpl*) pstm;
+ pStream = impl_from_IStream(pstm);
/*
* Verify that the stream object was created with CreateStreamOnHGlobal.
diff --git a/dlls/ole32/tests/hglobalstream.c b/dlls/ole32/tests/hglobalstream.c
index 2f386914af..5bcf9abfbd 100644
--- a/dlls/ole32/tests/hglobalstream.c
+++ b/dlls/ole32/tests/hglobalstream.c
@@ -561,6 +561,12 @@ static void test_IStream_Clone(void)
hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
ok(hr == S_OK, "unexpected %#x\n", hr);
+ hr = GetHGlobalFromStream(stream, NULL);
+ ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
+
+ hr = GetHGlobalFromStream(NULL, &hmem);
+ ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
+
stream_info(stream, &hmem, &size, &pos);
ok(hmem == orig_hmem, "handles should match\n");
ok(size == 0, "unexpected %d\n", size);
--
2.26.2
2
1
17 Aug '20
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/kernel32/tests/console.c | 4 ++++
dlls/kernelbase/console.c | 14 +++-----------
2 files changed, 7 insertions(+), 11 deletions(-)
2
1