windows.globalization: Implement IGlobalizationPreferencesStatics::Languages.

Returning user default language in a 1-element HSTRING vector.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-03-26 10:24:58 +01:00 committed by Alexandre Julliard
parent 6cffc2dc1a
commit 6302df9dc7
2 changed files with 222 additions and 5 deletions

View File

@ -48,6 +48,183 @@ static const char *debugstr_hstring(HSTRING hstr)
return wine_dbgstr_wn(str, len);
}
struct hstring_vector
{
IVectorView_HSTRING IVectorView_HSTRING_iface;
LONG ref;
ULONG count;
HSTRING values[1];
};
static inline struct hstring_vector *impl_from_IVectorView_HSTRING(IVectorView_HSTRING *iface)
{
return CONTAINING_RECORD(iface, struct hstring_vector, IVectorView_HSTRING_iface);
}
static HRESULT STDMETHODCALLTYPE hstring_vector_QueryInterface(IVectorView_HSTRING *iface,
REFIID iid, void **out)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out);
if (IsEqualGUID(iid, &IID_IUnknown) ||
IsEqualGUID(iid, &IID_IInspectable) ||
IsEqualGUID(iid, &IID_IAgileObject) ||
IsEqualGUID(iid, &IID_IVectorView_HSTRING))
{
IUnknown_AddRef(iface);
*out = &impl->IVectorView_HSTRING_iface;
return S_OK;
}
FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
*out = NULL;
return E_NOINTERFACE;
}
static ULONG STDMETHODCALLTYPE hstring_vector_AddRef(IVectorView_HSTRING *iface)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
ULONG ref = InterlockedIncrement(&impl->ref);
TRACE("iface %p, ref %u.\n", iface, ref);
return ref;
}
static ULONG STDMETHODCALLTYPE hstring_vector_Release(IVectorView_HSTRING *iface)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
ULONG ref = InterlockedDecrement(&impl->ref);
TRACE("iface %p, ref %u.\n", iface, ref);
if (ref == 0)
{
while (impl->count--) WindowsDeleteString(impl->values[impl->count]);
free(impl);
}
return ref;
}
static HRESULT STDMETHODCALLTYPE hstring_vector_GetIids(IVectorView_HSTRING *iface,
ULONG *iid_count, IID **iids)
{
FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE hstring_vector_GetRuntimeClassName(IVectorView_HSTRING *iface,
HSTRING *class_name)
{
FIXME("iface %p, class_name %p stub!\n", iface, class_name);
return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE hstring_vector_GetTrustLevel(IVectorView_HSTRING *iface,
TrustLevel *trust_level)
{
FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE hstring_vector_GetAt(IVectorView_HSTRING *iface,
ULONG index, HSTRING *value)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
TRACE("iface %p, index %#x, value %p.\n", iface, index, value);
*value = NULL;
if (index >= impl->count) return E_BOUNDS;
return WindowsDuplicateString(impl->values[index], value);
}
static HRESULT STDMETHODCALLTYPE hstring_vector_get_Size(IVectorView_HSTRING *iface,
ULONG *value)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
TRACE("iface %p, value %p.\n", iface, value);
*value = impl->count;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE hstring_vector_IndexOf(IVectorView_HSTRING *iface,
HSTRING element, ULONG *index, BOOLEAN *found)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
INT32 i, order;
TRACE("iface %p, element %p, index %p, found %p.\n", iface, element, index, found);
for (i = 0; i < impl->count; ++i)
if (SUCCEEDED(WindowsCompareStringOrdinal(impl->values[i], element, &order)) && order == 0)
break;
if (i < impl->count)
{
*found = TRUE;
*index = i;
}
else
{
*found = FALSE;
*index = 0;
}
return S_OK;
}
static HRESULT STDMETHODCALLTYPE hstring_vector_GetMany(IVectorView_HSTRING *iface,
ULONG start_index, ULONG items_size, HSTRING *items, UINT *count)
{
struct hstring_vector *impl = impl_from_IVectorView_HSTRING(iface);
HRESULT hr = S_OK;
ULONG i;
TRACE("iface %p, start_index %#x, items %p, count %p.\n", iface, start_index, items, count);
memset(items, 0, items_size * sizeof(HSTRING *));
for (i = start_index; i < impl->count && i < start_index + items_size; ++i)
if (FAILED(hr = WindowsDuplicateString(impl->values[i], items + i - start_index)))
break;
if (FAILED(hr)) while (i-- > start_index) WindowsDeleteString(items[i - start_index]);
*count = i - start_index;
return hr;
}
static const struct IVectorView_HSTRINGVtbl hstring_vector_vtbl =
{
hstring_vector_QueryInterface,
hstring_vector_AddRef,
hstring_vector_Release,
/* IInspectable methods */
hstring_vector_GetIids,
hstring_vector_GetRuntimeClassName,
hstring_vector_GetTrustLevel,
/* IVectorView<HSTRING> methods */
hstring_vector_GetAt,
hstring_vector_get_Size,
hstring_vector_IndexOf,
hstring_vector_GetMany,
};
static HRESULT hstring_vector_create(HSTRING *values, SIZE_T count, IVectorView_HSTRING **out)
{
struct hstring_vector *impl;
if (!(impl = malloc(offsetof(struct hstring_vector, values[count])))) return E_OUTOFMEMORY;
impl->ref = 1;
impl->IVectorView_HSTRING_iface.lpVtbl = &hstring_vector_vtbl;
impl->count = count;
memcpy(impl->values, values, count * sizeof(HSTRING));
*out = &impl->IVectorView_HSTRING_iface;
return S_OK;
}
struct windows_globalization
{
IActivationFactory IActivationFactory_iface;
@ -218,8 +395,21 @@ static HRESULT STDMETHODCALLTYPE globalization_preferences_get_Currencies(
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_Languages(
IGlobalizationPreferencesStatics *iface, IVectorView_HSTRING **out)
{
FIXME("iface %p, out %p stub!\n", iface, out);
return E_NOTIMPL;
HSTRING hstring;
HRESULT hr;
WCHAR locale[LOCALE_NAME_MAX_LENGTH];
TRACE("iface %p, out %p.\n", iface, out);
if (!GetUserDefaultLocaleName(locale, LOCALE_NAME_MAX_LENGTH))
return E_FAIL;
TRACE("returning language %s\n", debugstr_w(locale));
if (FAILED(hr = WindowsCreateString(locale, wcslen(locale), &hstring)))
return hr;
return hstring_vector_create(&hstring, 1, out);
}
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_HomeGeographicRegion(

View File

@ -108,8 +108,7 @@ static void test_GlobalizationPreferences(void)
pWindowsDeleteString(tmp_str);
hr = IGlobalizationPreferencesStatics_get_Languages(preferences_statics, &languages);
todo_wine ok(hr == S_OK, "IGlobalizationPreferencesStatics_get_Languages failed, hr %#x\n", hr);
if (FAILED(hr)) goto done;
ok(hr == S_OK, "IGlobalizationPreferencesStatics_get_Languages failed, hr %#x\n", hr);
hr = IVectorView_HSTRING_QueryInterface(languages, &IID_IInspectable, (void **)&tmp_inspectable);
ok(hr == S_OK, "IVectorView_HSTRING_QueryInterface failed, hr %#x\n", hr);
@ -143,14 +142,42 @@ static void test_GlobalizationPreferences(void)
pWindowsDeleteString(tmp_str);
hr = pWindowsCreateString(L"deadbeef", 8, &tmp_str);
ok(hr == S_OK, "WindowsCreateString failed, hr %#x\n", hr);
i = 0xdeadbeef;
found = TRUE;
hr = IVectorView_HSTRING_IndexOf(languages, tmp_str, &i, &found);
ok(hr == S_OK, "IVectorView_HSTRING_IndexOf failed, hr %#x\n", hr);
ok(i == 0 && found == FALSE, "IVectorView_HSTRING_IndexOf returned size %d, found %d\n", size, found);
pWindowsDeleteString(tmp_str);
tmp_str = (HSTRING)0xdeadbeef;
hr = IVectorView_HSTRING_GetAt(languages, size, &tmp_str);
ok(hr == E_BOUNDS, "IVectorView_HSTRING_GetAt failed, hr %#x\n", hr);
ok(tmp_str == NULL, "IVectorView_HSTRING_GetAt returned %p\n", tmp_str);
tmp_str = (HSTRING)0xdeadbeef;
hr = IVectorView_HSTRING_GetMany(languages, size, 1, &tmp_str, &i);
ok(hr == S_OK, "IVectorView_HSTRING_GetAt failed, hr %#x\n", hr);
ok(i == 0 && tmp_str == NULL, "IVectorView_HSTRING_GetMany returned count %u, str %p\n", i, tmp_str);
hr = IVectorView_HSTRING_GetMany(languages, 0, 1, &tmp_str, &i);
ok(hr == S_OK, "IVectorView_HSTRING_GetAt failed, hr %#x\n", hr);
ok(i == 1, "IVectorView_HSTRING_GetMany returned count %u, expected 1\n", i);
buf = pWindowsGetStringRawBuffer(tmp_str, &len);
ok(buf != NULL && len > 0, "WindowsGetStringRawBuffer returned buf %p, len %u\n", buf, len);
ok(wcslen(locale) == len && !memcmp(buf, locale, len),
"IGlobalizationPreferencesStatics_get_Languages 0 returned len %u, str %s, expected %s\n",
len, wine_dbgstr_w(buf), wine_dbgstr_w(locale));
pWindowsDeleteString(tmp_str);
IVectorView_HSTRING_Release(languages);
done:
IGlobalizationPreferencesStatics_Release(preferences_statics);
IAgileObject_Release(agile_object);