Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure.ac | 1 + dlls/windows.media.speech.dll/Makefile.in | 9 + dlls/windows.media.speech.dll/classes.idl | 19 +++ dlls/windows.media.speech.dll/main.c | 159 ++++++++++++++++++ .../windows.media.speech.spec | 3 + 5 files changed, 191 insertions(+) create mode 100644 dlls/windows.media.speech.dll/Makefile.in create mode 100644 dlls/windows.media.speech.dll/classes.idl create mode 100644 dlls/windows.media.speech.dll/main.c create mode 100644 dlls/windows.media.speech.dll/windows.media.speech.spec
diff --git a/configure.ac b/configure.ac index 6a4e9568c40..0e4329c99c4 100644 --- a/configure.ac +++ b/configure.ac @@ -3798,6 +3798,7 @@ WINE_CONFIG_MAKEFILE(dlls/win32s16.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/win87em.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winaspi.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/windebug.dll16,enable_win16) +WINE_CONFIG_MAKEFILE(dlls/windows.media.speech.dll) WINE_CONFIG_MAKEFILE(dlls/windowscodecs) WINE_CONFIG_MAKEFILE(dlls/windowscodecs/tests) WINE_CONFIG_MAKEFILE(dlls/windowscodecsext) diff --git a/dlls/windows.media.speech.dll/Makefile.in b/dlls/windows.media.speech.dll/Makefile.in new file mode 100644 index 00000000000..2c55daa04be --- /dev/null +++ b/dlls/windows.media.speech.dll/Makefile.in @@ -0,0 +1,9 @@ +MODULE = windows.media.speech.dll +IMPORTS = combase uuid + +EXTRADLLFLAGS = -mno-cygwin + +C_SRCS = \ + main.c + +IDL_SRCS = classes.idl diff --git a/dlls/windows.media.speech.dll/classes.idl b/dlls/windows.media.speech.dll/classes.idl new file mode 100644 index 00000000000..6c141bf4768 --- /dev/null +++ b/dlls/windows.media.speech.dll/classes.idl @@ -0,0 +1,19 @@ +/* + * 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 + */ + +#pragma makedep register + +#include "windows.media.speechsynthesis.idl" diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c new file mode 100644 index 00000000000..909ea6db748 --- /dev/null +++ b/dlls/windows.media.speech.dll/main.c @@ -0,0 +1,159 @@ +/* WinRT Windows.Media.Speech 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" + +#include "windows.foundation.h" +#include "windows.media.speechsynthesis.h" + +WINE_DEFAULT_DEBUG_CHANNEL(speech); + +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 windows_media_speech +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct windows_media_speech *impl_from_IActivationFactory(IActivationFactory *iface) +{ + return CONTAINING_RECORD(iface, struct windows_media_speech, IActivationFactory_iface); +} + +static HRESULT STDMETHODCALLTYPE windows_media_speech_QueryInterface( + IActivationFactory *iface, REFIID iid, void **out) +{ + struct windows_media_speech *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_IActivationFactory)) + { + IUnknown_AddRef(iface); + *out = &impl->IActivationFactory_iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE windows_media_speech_AddRef( + IActivationFactory *iface) +{ + struct windows_media_speech *impl = impl_from_IActivationFactory(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static ULONG STDMETHODCALLTYPE windows_media_speech_Release( + IActivationFactory *iface) +{ + struct windows_media_speech *impl = impl_from_IActivationFactory(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static HRESULT STDMETHODCALLTYPE windows_media_speech_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_media_speech_GetRuntimeClassName( + IActivationFactory *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE windows_media_speech_GetTrustLevel( + IActivationFactory *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE windows_media_speech_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_media_speech_QueryInterface, + windows_media_speech_AddRef, + windows_media_speech_Release, + /* IInspectable methods */ + windows_media_speech_GetIids, + windows_media_speech_GetRuntimeClassName, + windows_media_speech_GetTrustLevel, + /* IActivationFactory methods */ + windows_media_speech_ActivateInstance, +}; + +static struct windows_media_speech windows_media_speech = +{ + {&activation_factory_vtbl}, + 0 +}; + +HRESULT WINAPI DllCanUnloadNow(void) +{ + return S_FALSE; +} + +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_media_speech.IActivationFactory_iface; + IUnknown_AddRef(*factory); + return S_OK; +} diff --git a/dlls/windows.media.speech.dll/windows.media.speech.spec b/dlls/windows.media.speech.dll/windows.media.speech.spec new file mode 100644 index 00000000000..721493229c2 --- /dev/null +++ b/dlls/windows.media.speech.dll/windows.media.speech.spec @@ -0,0 +1,3 @@ +1 stdcall -private DllCanUnloadNow() +2 stdcall -private DllGetActivationFactory(ptr ptr) +3 stdcall -private DllGetClassObject(ptr ptr ptr)
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.media.speech.dll/main.c | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c index 909ea6db748..db57acac651 100644 --- a/dlls/windows.media.speech.dll/main.c +++ b/dlls/windows.media.speech.dll/main.c @@ -29,7 +29,10 @@ #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_Media_SpeechSynthesis #include "windows.media.speechsynthesis.h"
WINE_DEFAULT_DEBUG_CHANNEL(speech); @@ -46,6 +49,7 @@ static const char *debugstr_hstring(HSTRING hstr) struct windows_media_speech { IActivationFactory IActivationFactory_iface; + IInstalledVoicesStatic IInstalledVoicesStatic_iface; LONG ref; };
@@ -54,6 +58,98 @@ static inline struct windows_media_speech *impl_from_IActivationFactory(IActivat return CONTAINING_RECORD(iface, struct windows_media_speech, IActivationFactory_iface); }
+static inline struct windows_media_speech *impl_from_IInstalledVoicesStatic(IInstalledVoicesStatic *iface) +{ + return CONTAINING_RECORD(iface, struct windows_media_speech, IInstalledVoicesStatic_iface); +} + +static HRESULT STDMETHODCALLTYPE installed_voices_static_QueryInterface( + IInstalledVoicesStatic *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IInstalledVoicesStatic)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE installed_voices_static_AddRef( + IInstalledVoicesStatic *iface) +{ + struct windows_media_speech *impl = impl_from_IInstalledVoicesStatic(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static ULONG STDMETHODCALLTYPE installed_voices_static_Release( + IInstalledVoicesStatic *iface) +{ + struct windows_media_speech *impl = impl_from_IInstalledVoicesStatic(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static HRESULT STDMETHODCALLTYPE installed_voices_static_GetIids( + IInstalledVoicesStatic *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 installed_voices_static_GetRuntimeClassName( + IInstalledVoicesStatic *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE installed_voices_static_GetTrustLevel( + IInstalledVoicesStatic *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE installed_voices_static_get_AllVoices( + IInstalledVoicesStatic *iface, IVectorView_VoiceInformation **value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE installed_voices_static_get_DefaultVoice( + IInstalledVoicesStatic *iface, IVoiceInformation **value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static const struct IInstalledVoicesStaticVtbl installed_voices_static_vtbl = +{ + installed_voices_static_QueryInterface, + installed_voices_static_AddRef, + installed_voices_static_Release, + /* IInspectable methods */ + installed_voices_static_GetIids, + installed_voices_static_GetRuntimeClassName, + installed_voices_static_GetTrustLevel, + /* IInstalledVoicesStatic methods */ + installed_voices_static_get_AllVoices, + installed_voices_static_get_DefaultVoice, +}; + static HRESULT STDMETHODCALLTYPE windows_media_speech_QueryInterface( IActivationFactory *iface, REFIID iid, void **out) { @@ -69,6 +165,13 @@ static HRESULT STDMETHODCALLTYPE windows_media_speech_QueryInterface( return S_OK; }
+ if (IsEqualGUID(iid, &IID_IInstalledVoicesStatic)) + { + IUnknown_AddRef(iface); + *out = &impl->IInstalledVoicesStatic_iface; + return S_OK; + } + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -136,6 +239,7 @@ static const struct IActivationFactoryVtbl activation_factory_vtbl = static struct windows_media_speech windows_media_speech = { {&activation_factory_vtbl}, + {&installed_voices_static_vtbl}, 0 };
Hi Rémi,
The series looks better now, but it has some COM problems. Also, there is not much to test yet, but it would still be interesting to see some basic creation and QueryInterface tests.
On 05.03.2021 09:53, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/windows.media.speech.dll/main.c | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c index 909ea6db748..db57acac651 100644 --- a/dlls/windows.media.speech.dll/main.c +++ b/dlls/windows.media.speech.dll/main.c @@ -29,7 +29,10 @@ #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_Media_SpeechSynthesis #include "windows.media.speechsynthesis.h"
WINE_DEFAULT_DEBUG_CHANNEL(speech); @@ -46,6 +49,7 @@ static const char *debugstr_hstring(HSTRING hstr) struct windows_media_speech { IActivationFactory IActivationFactory_iface;
- IInstalledVoicesStatic IInstalledVoicesStatic_iface; LONG ref; };
@@ -54,6 +58,98 @@ static inline struct windows_media_speech *impl_from_IActivationFactory(IActivat return CONTAINING_RECORD(iface, struct windows_media_speech, IActivationFactory_iface); }
+static inline struct windows_media_speech *impl_from_IInstalledVoicesStatic(IInstalledVoicesStatic *iface) +{
- return CONTAINING_RECORD(iface, struct windows_media_speech, IInstalledVoicesStatic_iface);
+}
+static HRESULT STDMETHODCALLTYPE installed_voices_static_QueryInterface(
IInstalledVoicesStatic *iface, REFIID iid, void **out)
+{
- TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out);
- if (IsEqualGUID(iid, &IID_IUnknown) ||
IsEqualGUID(iid, &IID_IAgileObject) ||
IsEqualGUID(iid, &IID_IInspectable) ||
IsEqualGUID(iid, &IID_IInstalledVoicesStatic))
- {
IUnknown_AddRef(iface);
*out = iface;
return S_OK;
- }
- WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
- *out = NULL;
- return E_NOINTERFACE;
+}
It's missing IActivationFactrory interface.
@@ -69,6 +165,13 @@ static HRESULT STDMETHODCALLTYPE windows_media_speech_QueryInterface( return S_OK; }
- if (IsEqualGUID(iid, &IID_IInstalledVoicesStatic))
- {
IUnknown_AddRef(iface);
*out = &impl->IInstalledVoicesStatic_iface;
return S_OK;
- }
It's missing IID_IAgileObject interface now and it generally just duplicates installed_voices_static_QueryInterface. The usual practice is to have one QueryInterface implementation per object and forward other calls. Same for AddRef and Release (at least in case where we have actual ref counting).
Note static objects don't need ref counting at all, because you don't have the destructor anyway. If there is a reason to have reference counting, then patch 3 is missing AddRef call.
Static object also don't really need a structs like windows_media_speech, but it's fine to have it. However, IVectorView_VoiceInformation doesn't really belong to windows_media_speech object as it looks like a separate object.
Thanks,
Jacek
On 3/5/21 2:51 PM, Jacek Caban wrote:
Hi Rémi,
The series looks better now, but it has some COM problems. Also, there is not much to test yet, but it would still be interesting to see some basic creation and QueryInterface tests.
Alright, I can add a few tests.
On 05.03.2021 09:53, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/windows.media.speech.dll/main.c | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c index 909ea6db748..db57acac651 100644 --- a/dlls/windows.media.speech.dll/main.c +++ b/dlls/windows.media.speech.dll/main.c @@ -29,7 +29,10 @@ #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_Media_SpeechSynthesis #include "windows.media.speechsynthesis.h" WINE_DEFAULT_DEBUG_CHANNEL(speech); @@ -46,6 +49,7 @@ static const char *debugstr_hstring(HSTRING hstr) struct windows_media_speech { IActivationFactory IActivationFactory_iface; + IInstalledVoicesStatic IInstalledVoicesStatic_iface; LONG ref; }; @@ -54,6 +58,98 @@ static inline struct windows_media_speech *impl_from_IActivationFactory(IActivat return CONTAINING_RECORD(iface, struct windows_media_speech, IActivationFactory_iface); } +static inline struct windows_media_speech *impl_from_IInstalledVoicesStatic(IInstalledVoicesStatic *iface) +{ + return CONTAINING_RECORD(iface, struct windows_media_speech, IInstalledVoicesStatic_iface); +}
+static HRESULT STDMETHODCALLTYPE installed_voices_static_QueryInterface( + IInstalledVoicesStatic *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out);
+ if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IInstalledVoicesStatic)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + }
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +}
It's missing IActivationFactrory interface.
@@ -69,6 +165,13 @@ static HRESULT STDMETHODCALLTYPE windows_media_speech_QueryInterface( return S_OK; } + if (IsEqualGUID(iid, &IID_IInstalledVoicesStatic)) + { + IUnknown_AddRef(iface); + *out = &impl->IInstalledVoicesStatic_iface; + return S_OK; + }
It's missing IID_IAgileObject interface now and it generally just duplicates installed_voices_static_QueryInterface. The usual practice is to have one QueryInterface implementation per object and forward other calls. Same for AddRef and Release (at least in case where we have actual ref counting).
Note static objects don't need ref counting at all, because you don't have the destructor anyway. If there is a reason to have reference counting, then patch 3 is missing AddRef call.
From basic tests it looks like it's supposed to be actually refcounted on Windows, and destructed if released too many times. I'm not sure if it's worth implementing such behavior?
Static object also don't really need a structs like windows_media_speech, but it's fine to have it. However, IVectorView_VoiceInformation doesn't really belong to windows_media_speech object as it looks like a separate object.
Yeah, that was mainly for convenience, as it was only meant to be a stub.
Thanks,
Jacek
Cheers,
On 05.03.2021 16:12, Rémi Bernon wrote:
On 3/5/21 2:51 PM, Jacek Caban wrote:
It's missing IID_IAgileObject interface now and it generally just duplicates installed_voices_static_QueryInterface. The usual practice is to have one QueryInterface implementation per object and forward other calls. Same for AddRef and Release (at least in case where we have actual ref counting).
Note static objects don't need ref counting at all, because you don't have the destructor anyway. If there is a reason to have reference counting, then patch 3 is missing AddRef call.
From basic tests it looks like it's supposed to be actually refcounted on Windows, and destructed if released too many times. I'm not sure if it's worth implementing such behavior?
In my opinion, it's not interesting to follow Windows in such cases (but I wouldn't mind it, as long as COM rules are followed).
Jacek
On 3/5/21 7:51 AM, Jacek Caban wrote:
Hi Rémi,
The series looks better now, but it has some COM problems. Also, there is not much to test yet, but it would still be interesting to see some basic creation and QueryInterface tests.
On 05.03.2021 09:53, Rémi Bernon wrote:
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/windows.media.speech.dll/main.c | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c index 909ea6db748..db57acac651 100644 --- a/dlls/windows.media.speech.dll/main.c +++ b/dlls/windows.media.speech.dll/main.c @@ -29,7 +29,10 @@ #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_Media_SpeechSynthesis #include "windows.media.speechsynthesis.h"
WINE_DEFAULT_DEBUG_CHANNEL(speech); @@ -46,6 +49,7 @@ static const char *debugstr_hstring(HSTRING hstr) struct windows_media_speech { IActivationFactory IActivationFactory_iface;
- IInstalledVoicesStatic IInstalledVoicesStatic_iface; LONG ref; };
@@ -54,6 +58,98 @@ static inline struct windows_media_speech *impl_from_IActivationFactory(IActivat return CONTAINING_RECORD(iface, struct windows_media_speech, IActivationFactory_iface); }
+static inline struct windows_media_speech *impl_from_IInstalledVoicesStatic(IInstalledVoicesStatic *iface) +{
- return CONTAINING_RECORD(iface, struct windows_media_speech, IInstalledVoicesStatic_iface);
+}
+static HRESULT STDMETHODCALLTYPE installed_voices_static_QueryInterface(
IInstalledVoicesStatic *iface, REFIID iid, void **out)
+{
- TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out);
- if (IsEqualGUID(iid, &IID_IUnknown) ||
IsEqualGUID(iid, &IID_IAgileObject) ||
IsEqualGUID(iid, &IID_IInspectable) ||
IsEqualGUID(iid, &IID_IInstalledVoicesStatic))
- {
IUnknown_AddRef(iface);
*out = iface;
return S_OK;
- }
- WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
- *out = NULL;
- return E_NOINTERFACE;
+}
It's missing IActivationFactrory interface.
@@ -69,6 +165,13 @@ static HRESULT STDMETHODCALLTYPE windows_media_speech_QueryInterface( return S_OK; }
- if (IsEqualGUID(iid, &IID_IInstalledVoicesStatic))
- {
IUnknown_AddRef(iface);
*out = &impl->IInstalledVoicesStatic_iface;
return S_OK;
- }
It's missing IID_IAgileObject interface now and it generally just duplicates installed_voices_static_QueryInterface. The usual practice is to have one QueryInterface implementation per object and forward other calls. Same for AddRef and Release (at least in case where we have actual ref counting).
Note static objects don't need ref counting at all, because you don't have the destructor anyway. If there is a reason to have reference counting, then patch 3 is missing AddRef call.
Static object also don't really need a structs like windows_media_speech, but it's fine to have it. However, IVectorView_VoiceInformation doesn't really belong to windows_media_speech object as it looks like a separate object.
As far as I can tell, it's not a mutable interface and therefore doesn't need to be made into a separate object, right?
Thanks,
Jacek
On 05.03.2021 17:21, Zebediah Figura (she/her) wrote:
Static object also don't really need a structs like windows_media_speech, but it's fine to have it. However, IVectorView_VoiceInformation doesn't really belong to windows_media_speech object as it looks like a separate object.
As far as I can tell, it's not a mutable interface and therefore doesn't need to be made into a separate object, right?
I assume that by separated object you mean separated C structs to represent multiple COM objects. If we have separated QueryInterface implementations, then we deal with separated COM objects even if they are represented by a single C struct (and share ref count, which is not great).
And yes, technically it doesn't need to be a separated struct, but when I look at something like that:
struct windows_media_speech
{ IActivationFactory IActivationFactory_iface; IInstalledVoicesStatic IInstalledVoicesStatic_iface; IVectorView_VoiceInformation IVectorView_VoiceInformation_iface; LONG ref; };
the first (and usually right) impression is that it's an object that implements 3 interfaces (as in, any of its QueryInterfaces will support all those interfaces). And yet in this case it's not true. I'd really need to read all QueryInterface implementations to learn that it's really a struct representing two separated COM object. It could be clarified with a comment, but I don't really see why in this particular case we'd want a single struct at all. It doesn't seem to be making anything easier. There are cases when something like that may be useful, but this one doesn't seem one of them.
BTW, as long as those object implement ref counting, they are not exactly immutable.
Jacek
On 3/5/21 1:02 PM, Jacek Caban wrote:
On 05.03.2021 17:21, Zebediah Figura (she/her) wrote:
Static object also don't really need a structs like windows_media_speech, but it's fine to have it. However, IVectorView_VoiceInformation doesn't really belong to windows_media_speech object as it looks like a separate object.
As far as I can tell, it's not a mutable interface and therefore doesn't need to be made into a separate object, right?
I assume that by separated object you mean separated C structs to represent multiple COM objects. If we have separated QueryInterface implementations, then we deal with separated COM objects even if they are represented by a single C struct (and share ref count, which is not great).
And yes, technically it doesn't need to be a separated struct, but when I look at something like that:
struct windows_media_speech
{ IActivationFactory IActivationFactory_iface; IInstalledVoicesStatic IInstalledVoicesStatic_iface; IVectorView_VoiceInformation IVectorView_VoiceInformation_iface; LONG ref; };
the first (and usually right) impression is that it's an object that implements 3 interfaces (as in, any of its QueryInterfaces will support all those interfaces). And yet in this case it's not true. I'd really need to read all QueryInterface implementations to learn that it's really a struct representing two separated COM object. It could be clarified with a comment, but I don't really see why in this particular case we'd want a single struct at all. It doesn't seem to be making anything easier. There are cases when something like that may be useful, but this one doesn't seem one of them.
Well, it's one less allocation, which is always nice.
Definitely the interface should be visually separated in the windows_media_speech structure, though.
BTW, as long as those object implement ref counting, they are not exactly immutable.
True, but I at least hope we're past the point where programs abuse COM refcounting all the time, and that nonsense can be confined to things like ddraw and dmusic ;-)
Jacek
On 05.03.2021 22:06, Zebediah Figura (she/her) wrote:
Well, it's one less allocation, which is always nice.
Definitely the interface should be visually separated in the windows_media_speech structure, though.
Again, it's a static object so no allocation is needed at all. And even if it was, it sounds to me like encouraging micro-optimization.
BTW, as long as those object implement ref counting, they are not exactly immutable.
True, but I at least hope we're past the point where programs abuse COM refcounting all the time, and that nonsense can be confined to things like ddraw and dmusic ;-)
Yup, that's why we usually don't need to replicate the exact native ref count behaviour. That doesn't mean we shouldn't do it right.
Jacek
On 3/5/21 10:06 PM, Zebediah Figura (she/her) wrote:
BTW, as long as those object implement ref counting, they are not exactly immutable.
True, but I at least hope we're past the point where programs abuse COM refcounting all the time, and that nonsense can be confined to things like ddraw and dmusic ;-)
Give dmusic a break please. You can blame it for a lot of things but not really for COM. The COM implementations there are pretty standard.
If you want bad COM I can recommend you dplayx.
bye michael
On Fri, 5 Mar 2021 at 22:25, Michael Stefaniuc mstefani@winehq.org wrote:
On 3/5/21 10:06 PM, Zebediah Figura (she/her) wrote:
BTW, as long as those object implement ref counting, they are not exactly immutable.
True, but I at least hope we're past the point where programs abuse COM refcounting all the time, and that nonsense can be confined to things like ddraw and dmusic ;-)
Give dmusic a break please. You can blame it for a lot of things but not really for COM. The COM implementations there are pretty standard.
Applications from that era definitely use COM in unnatural ways though.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.media.speech.dll/main.c | 113 ++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-)
diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c index db57acac651..c5ca9528e35 100644 --- a/dlls/windows.media.speech.dll/main.c +++ b/dlls/windows.media.speech.dll/main.c @@ -50,6 +50,7 @@ struct windows_media_speech { IActivationFactory IActivationFactory_iface; IInstalledVoicesStatic IInstalledVoicesStatic_iface; + IVectorView_VoiceInformation IVectorView_VoiceInformation_iface; LONG ref; };
@@ -63,6 +64,113 @@ static inline struct windows_media_speech *impl_from_IInstalledVoicesStatic(IIns return CONTAINING_RECORD(iface, struct windows_media_speech, IInstalledVoicesStatic_iface); }
+static inline struct windows_media_speech *impl_from_IVectorView_VoiceInformation(IVectorView_VoiceInformation *iface) +{ + return CONTAINING_RECORD(iface, struct windows_media_speech, IVectorView_VoiceInformation_iface); +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_QueryInterface( + IVectorView_VoiceInformation *iface, REFIID iid, void **out) +{ + 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_IVectorView_VoiceInformation)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE vector_view_voice_information_AddRef( + IVectorView_VoiceInformation *iface) +{ + struct windows_media_speech *impl = impl_from_IVectorView_VoiceInformation(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static ULONG STDMETHODCALLTYPE vector_view_voice_information_Release( + IVectorView_VoiceInformation *iface) +{ + struct windows_media_speech *impl = impl_from_IVectorView_VoiceInformation(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_GetIids( + IVectorView_VoiceInformation *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 vector_view_voice_information_GetRuntimeClassName( + IVectorView_VoiceInformation *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_GetTrustLevel( + IVectorView_VoiceInformation *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_GetAt( + IVectorView_VoiceInformation *iface, ULONG index, IVoiceInformation **value) +{ + FIXME("iface %p, index %#x, value %p stub!\n", iface, index, value); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_get_Size( + IVectorView_VoiceInformation *iface, ULONG *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_IndexOf( + IVectorView_VoiceInformation *iface, IVoiceInformation *element, ULONG *index, BOOLEAN *value) +{ + FIXME("iface %p, element %p, index %p, value %p stub!\n", iface, element, index, value); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE vector_view_voice_information_GetMany( + IVectorView_VoiceInformation *iface, ULONG start_index, IVoiceInformation **items, UINT *value) +{ + FIXME("iface %p, start_index %#x, items %p, value %p stub!\n", iface, start_index, items, value); + return E_NOTIMPL; +} + +static const struct IVectorView_VoiceInformationVtbl vector_view_voice_information_vtbl = +{ + vector_view_voice_information_QueryInterface, + vector_view_voice_information_AddRef, + vector_view_voice_information_Release, + /* IInspectable methods */ + vector_view_voice_information_GetIids, + vector_view_voice_information_GetRuntimeClassName, + vector_view_voice_information_GetTrustLevel, + /* IVectorView<VoiceInformation> methods */ + vector_view_voice_information_GetAt, + vector_view_voice_information_get_Size, + vector_view_voice_information_IndexOf, + vector_view_voice_information_GetMany, +}; + static HRESULT STDMETHODCALLTYPE installed_voices_static_QueryInterface( IInstalledVoicesStatic *iface, REFIID iid, void **out) { @@ -125,8 +233,10 @@ static HRESULT STDMETHODCALLTYPE installed_voices_static_GetTrustLevel( static HRESULT STDMETHODCALLTYPE installed_voices_static_get_AllVoices( IInstalledVoicesStatic *iface, IVectorView_VoiceInformation **value) { + struct windows_media_speech *impl = impl_from_IInstalledVoicesStatic(iface); FIXME("iface %p, value %p stub!\n", iface, value); - return E_NOTIMPL; + *value = &impl->IVectorView_VoiceInformation_iface; + return S_OK; }
static HRESULT STDMETHODCALLTYPE installed_voices_static_get_DefaultVoice( @@ -240,6 +350,7 @@ static struct windows_media_speech windows_media_speech = { {&activation_factory_vtbl}, {&installed_voices_static_vtbl}, + {&vector_view_voice_information_vtbl}, 0 };
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.media.speech.dll/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/windows.media.speech.dll/main.c b/dlls/windows.media.speech.dll/main.c index c5ca9528e35..1add3425e2b 100644 --- a/dlls/windows.media.speech.dll/main.c +++ b/dlls/windows.media.speech.dll/main.c @@ -131,28 +131,31 @@ static HRESULT STDMETHODCALLTYPE vector_view_voice_information_GetAt( IVectorView_VoiceInformation *iface, ULONG index, IVoiceInformation **value) { FIXME("iface %p, index %#x, value %p stub!\n", iface, index, value); - return E_NOTIMPL; + return S_OK; }
static HRESULT STDMETHODCALLTYPE vector_view_voice_information_get_Size( IVectorView_VoiceInformation *iface, ULONG *value) { FIXME("iface %p, value %p stub!\n", iface, value); - return E_NOTIMPL; + *value = 0; + return S_OK; }
static HRESULT STDMETHODCALLTYPE vector_view_voice_information_IndexOf( IVectorView_VoiceInformation *iface, IVoiceInformation *element, ULONG *index, BOOLEAN *value) { FIXME("iface %p, element %p, index %p, value %p stub!\n", iface, element, index, value); - return E_NOTIMPL; + *value = FALSE; + return S_OK; }
static HRESULT STDMETHODCALLTYPE vector_view_voice_information_GetMany( IVectorView_VoiceInformation *iface, ULONG start_index, IVoiceInformation **items, UINT *value) { FIXME("iface %p, start_index %#x, items %p, value %p stub!\n", iface, start_index, items, value); - return E_NOTIMPL; + *value = 0; + return S_OK; }
static const struct IVectorView_VoiceInformationVtbl vector_view_voice_information_vtbl =