475 lines
15 KiB
C
475 lines
15 KiB
C
/* WinRT Windows.Globalization implementation
|
|
*
|
|
* Copyright 2021 Rémi Bernon for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#define COBJMACROS
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winstring.h"
|
|
#include "wine/debug.h"
|
|
#include "objbase.h"
|
|
|
|
#include "initguid.h"
|
|
#include "activation.h"
|
|
|
|
#define WIDL_using_Windows_Foundation
|
|
#define WIDL_using_Windows_Foundation_Collections
|
|
#include "windows.foundation.h"
|
|
#define WIDL_using_Windows_Globalization
|
|
#include "windows.globalization.h"
|
|
#define WIDL_using_Windows_System_UserProfile
|
|
#include "windows.system.userprofile.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(locale);
|
|
|
|
static const char *debugstr_hstring(HSTRING hstr)
|
|
{
|
|
const WCHAR *str;
|
|
UINT32 len;
|
|
if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)";
|
|
str = WindowsGetStringRawBuffer(hstr, &len);
|
|
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(*items));
|
|
|
|
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;
|
|
IGlobalizationPreferencesStatics IGlobalizationPreferencesStatics_iface;
|
|
LONG ref;
|
|
};
|
|
|
|
static inline struct windows_globalization *impl_from_IActivationFactory(IActivationFactory *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct windows_globalization, IActivationFactory_iface);
|
|
}
|
|
|
|
static inline struct windows_globalization *impl_from_IGlobalizationPreferencesStatics(IGlobalizationPreferencesStatics *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct windows_globalization, IGlobalizationPreferencesStatics_iface);
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE windows_globalization_QueryInterface(
|
|
IActivationFactory *iface, REFIID iid, void **out)
|
|
{
|
|
struct windows_globalization *impl = impl_from_IActivationFactory(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_IActivationFactory))
|
|
{
|
|
IUnknown_AddRef(iface);
|
|
*out = &impl->IActivationFactory_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
if (IsEqualGUID(iid, &IID_IGlobalizationPreferencesStatics))
|
|
{
|
|
IUnknown_AddRef(iface);
|
|
*out = &impl->IGlobalizationPreferencesStatics_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG STDMETHODCALLTYPE windows_globalization_AddRef(
|
|
IActivationFactory *iface)
|
|
{
|
|
struct windows_globalization *impl = impl_from_IActivationFactory(iface);
|
|
ULONG ref = InterlockedIncrement(&impl->ref);
|
|
TRACE("iface %p, ref %u.\n", iface, ref);
|
|
return ref;
|
|
}
|
|
|
|
static ULONG STDMETHODCALLTYPE windows_globalization_Release(
|
|
IActivationFactory *iface)
|
|
{
|
|
struct windows_globalization *impl = impl_from_IActivationFactory(iface);
|
|
ULONG ref = InterlockedDecrement(&impl->ref);
|
|
TRACE("iface %p, ref %u.\n", iface, ref);
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE windows_globalization_GetIids(
|
|
IActivationFactory *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 windows_globalization_GetRuntimeClassName(
|
|
IActivationFactory *iface, HSTRING *class_name)
|
|
{
|
|
FIXME("iface %p, class_name %p stub!\n", iface, class_name);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE windows_globalization_GetTrustLevel(
|
|
IActivationFactory *iface, TrustLevel *trust_level)
|
|
{
|
|
FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE windows_globalization_ActivateInstance(
|
|
IActivationFactory *iface, IInspectable **instance)
|
|
{
|
|
FIXME("iface %p, instance %p stub!\n", iface, instance);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const struct IActivationFactoryVtbl activation_factory_vtbl =
|
|
{
|
|
windows_globalization_QueryInterface,
|
|
windows_globalization_AddRef,
|
|
windows_globalization_Release,
|
|
/* IInspectable methods */
|
|
windows_globalization_GetIids,
|
|
windows_globalization_GetRuntimeClassName,
|
|
windows_globalization_GetTrustLevel,
|
|
/* IActivationFactory methods */
|
|
windows_globalization_ActivateInstance,
|
|
};
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_QueryInterface(
|
|
IGlobalizationPreferencesStatics *iface, REFIID iid, void **object)
|
|
{
|
|
struct windows_globalization *impl = impl_from_IGlobalizationPreferencesStatics(iface);
|
|
return windows_globalization_QueryInterface(&impl->IActivationFactory_iface, iid, object);
|
|
}
|
|
|
|
static ULONG STDMETHODCALLTYPE globalization_preferences_AddRef(
|
|
IGlobalizationPreferencesStatics *iface)
|
|
{
|
|
struct windows_globalization *impl = impl_from_IGlobalizationPreferencesStatics(iface);
|
|
return windows_globalization_AddRef(&impl->IActivationFactory_iface);
|
|
}
|
|
|
|
static ULONG STDMETHODCALLTYPE globalization_preferences_Release(
|
|
IGlobalizationPreferencesStatics *iface)
|
|
{
|
|
struct windows_globalization *impl = impl_from_IGlobalizationPreferencesStatics(iface);
|
|
return windows_globalization_Release(&impl->IActivationFactory_iface);
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_GetIids(
|
|
IGlobalizationPreferencesStatics *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 globalization_preferences_GetRuntimeClassName(
|
|
IGlobalizationPreferencesStatics *iface, HSTRING *class_name)
|
|
{
|
|
FIXME("iface %p, class_name %p stub!\n", iface, class_name);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_GetTrustLevel(
|
|
IGlobalizationPreferencesStatics *iface, TrustLevel *trust_level)
|
|
{
|
|
FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_Calendars(
|
|
IGlobalizationPreferencesStatics *iface, IVectorView_HSTRING **out)
|
|
{
|
|
FIXME("iface %p, out %p stub!\n", iface, out);
|
|
return hstring_vector_create(NULL, 0, out);
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_Clocks(
|
|
IGlobalizationPreferencesStatics *iface, IVectorView_HSTRING **out)
|
|
{
|
|
FIXME("iface %p, out %p stub!\n", iface, out);
|
|
return hstring_vector_create(NULL, 0, out);
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_Currencies(
|
|
IGlobalizationPreferencesStatics *iface, IVectorView_HSTRING **out)
|
|
{
|
|
FIXME("iface %p, out %p stub!\n", iface, out);
|
|
return hstring_vector_create(NULL, 0, out);
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_Languages(
|
|
IGlobalizationPreferencesStatics *iface, IVectorView_HSTRING **out)
|
|
{
|
|
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(
|
|
IGlobalizationPreferencesStatics *iface, HSTRING* out)
|
|
{
|
|
WCHAR country[16];
|
|
|
|
TRACE("iface %p, out %p.\n", iface, out);
|
|
|
|
if (!GetUserDefaultGeoName(country, 16))
|
|
return E_FAIL;
|
|
|
|
TRACE("returning country %s\n", debugstr_w(country));
|
|
|
|
return WindowsCreateString(country, wcslen(country), out);
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE globalization_preferences_get_WeekStartsOn(
|
|
IGlobalizationPreferencesStatics *iface, enum DayOfWeek* out)
|
|
{
|
|
FIXME("iface %p, out %p stub!\n", iface, out);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const struct IGlobalizationPreferencesStaticsVtbl globalization_preferences_vtbl =
|
|
{
|
|
globalization_preferences_QueryInterface,
|
|
globalization_preferences_AddRef,
|
|
globalization_preferences_Release,
|
|
/* IInspectable methods */
|
|
globalization_preferences_GetIids,
|
|
globalization_preferences_GetRuntimeClassName,
|
|
globalization_preferences_GetTrustLevel,
|
|
/* IGlobalizationPreferencesStatics methods */
|
|
globalization_preferences_get_Calendars,
|
|
globalization_preferences_get_Clocks,
|
|
globalization_preferences_get_Currencies,
|
|
globalization_preferences_get_Languages,
|
|
globalization_preferences_get_HomeGeographicRegion,
|
|
globalization_preferences_get_WeekStartsOn,
|
|
};
|
|
|
|
static struct windows_globalization windows_globalization =
|
|
{
|
|
{&activation_factory_vtbl},
|
|
{&globalization_preferences_vtbl},
|
|
0
|
|
};
|
|
|
|
HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
|
|
{
|
|
FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out);
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory)
|
|
{
|
|
TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory);
|
|
*factory = &windows_globalization.IActivationFactory_iface;
|
|
IUnknown_AddRef(*factory);
|
|
return S_OK;
|
|
}
|