Module: wine Branch: master Commit: 6302df9dc7b277ec30fd12c5a0fe2e4b8f933b1b URL: https://source.winehq.org/git/wine.git/?a=commit;h=6302df9dc7b277ec30fd12c5a...
Author: Rémi Bernon rbernon@codeweavers.com Date: Fri Mar 26 10:24:58 2021 +0100
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
---
dlls/windows.globalization/main.c | 194 ++++++++++++++++++++++- dlls/windows.globalization/tests/globalization.c | 33 +++- 2 files changed, 222 insertions(+), 5 deletions(-)
diff --git a/dlls/windows.globalization/main.c b/dlls/windows.globalization/main.c index 84813152047..9aa07700310 100644 --- a/dlls/windows.globalization/main.c +++ b/dlls/windows.globalization/main.c @@ -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( diff --git a/dlls/windows.globalization/tests/globalization.c b/dlls/windows.globalization/tests/globalization.c index 00d9cee5b0d..a2b47e53be5 100644 --- a/dlls/windows.globalization/tests/globalization.c +++ b/dlls/windows.globalization/tests/globalization.c @@ -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);