[PATCH 2/4] sapi: Add stubs for SpObjectToken.

Myah Caron qsniyg at protonmail.com
Tue Sep 15 23:35:12 CDT 2020


Signed-off-by: Myah Caron <qsniyg at protonmail.com>
---
This patchset is progressing further towards fixing https://bugs.winehq.org/show_bug.cgi?id=49641

Though the tests reference GetCategory, it would require a fair amount of work to
implement, so I've left it out of this patchset. I've kept the tests however, as
they reveal some information about SetId (the primary target of this patchset).


 dlls/sapi/main.c           |   3 +
 dlls/sapi/sapi_classes.idl |  13 ++
 dlls/sapi/sapi_private.h   |   1 +
 dlls/sapi/tests/token.c    | 124 +++++++++++++++++
 dlls/sapi/token.c          | 276 +++++++++++++++++++++++++++++++++++++
 include/sapi.idl           |  13 ++
 6 files changed, 430 insertions(+)

diff --git a/dlls/sapi/main.c b/dlls/sapi/main.c
index e8d4ae01583..9c644001faa 100644
--- a/dlls/sapi/main.c
+++ b/dlls/sapi/main.c
@@ -110,6 +110,7 @@ static struct class_factory file_stream_cf    = { { &class_factory_vtbl }, file_
 static struct class_factory speech_voice_cf   = { { &class_factory_vtbl }, speech_voice_create };
 static struct class_factory token_category_cf = { { &class_factory_vtbl }, token_category_create };
 static struct class_factory token_enum_cf     = { { &class_factory_vtbl }, token_enum_create };
+static struct class_factory token_cf          = { { &class_factory_vtbl }, token_create };

 /******************************************************************
  *             DllGetClassObject
@@ -128,6 +129,8 @@ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **obj )
         cf = &token_category_cf.IClassFactory_iface;
     else if (IsEqualCLSID( clsid, &CLSID_SpObjectTokenEnum ))
         cf = &token_enum_cf.IClassFactory_iface;
+    else if (IsEqualCLSID( clsid, &CLSID_SpObjectToken ))
+        cf = &token_cf.IClassFactory_iface;
     else if (IsEqualCLSID( clsid, &CLSID_SpVoice ))
         cf = &speech_voice_cf.IClassFactory_iface;

diff --git a/dlls/sapi/sapi_classes.idl b/dlls/sapi/sapi_classes.idl
index ed86d166fcd..082244e0812 100644
--- a/dlls/sapi/sapi_classes.idl
+++ b/dlls/sapi/sapi_classes.idl
@@ -51,6 +51,19 @@ coclass SpObjectTokenEnum
     [default] interface IEnumSpObjectTokens;
 }

+[
+    uuid(ef411752-3736-4cb4-9c8c-8ef4ccb58efe),
+    helpstring("Object Token"),
+    progid("SAPI.SpObjectToken.1"),
+    vi_progid("SAPI.SpObjectToken"),
+    threading(both)
+]
+coclass SpObjectToken
+{
+    interface ISpObjectToken;
+    [default] interface ISpDataKey;
+}
+
 [
     uuid(96749377-3391-11d2-9ee3-00c04f797396),
     helpstring("Speech Voice"),
diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h
index e9fed0ea443..414dea2755a 100644
--- a/dlls/sapi/sapi_private.h
+++ b/dlls/sapi/sapi_private.h
@@ -25,6 +25,7 @@ HRESULT file_stream_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_H
 HRESULT speech_voice_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
 HRESULT token_category_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
 HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
+HRESULT token_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;

 static inline LPWSTR heap_strdupW(LPCWSTR str)
 {
diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c
index 58d69920fd5..9558022b3f4 100644
--- a/dlls/sapi/tests/token.c
+++ b/dlls/sapi/tests/token.c
@@ -174,6 +174,129 @@ static void test_default_token_id(void)
     ISpObjectTokenCategory_Release( cat );
 }

+static void test_object_token(void)
+{
+    ISpObjectToken *token;
+    HRESULT hr;
+    LPWSTR tempW, token_id;
+    ISpObjectTokenCategory *cat;
+
+    hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER,
+                           &IID_ISpObjectToken, (void **)&token );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = ISpObjectToken_GetId( token, NULL );
+    todo_wine ok( hr == SPERR_UNINITIALIZED, "got %08x\n", hr );
+
+    tempW = (LPWSTR)0xdeadbeef;
+    hr = ISpObjectToken_GetId( token, &tempW );
+    todo_wine ok( hr == SPERR_UNINITIALIZED, "got %08x\n", hr );
+    ok( tempW == (LPWSTR)0xdeadbeef, "got %s\n", wine_dbgstr_w(tempW) );
+
+    hr = ISpObjectToken_GetCategory( token, NULL );
+    todo_wine ok( hr == SPERR_UNINITIALIZED, "got %08x\n", hr );
+
+    cat = (LPVOID)0xdeadbeef;
+    hr = ISpObjectToken_GetCategory( token, &cat );
+    todo_wine ok( hr == SPERR_UNINITIALIZED, "got %08x\n", hr );
+    ok( cat == (LPVOID)0xdeadbeef, "got %p\n", cat );
+
+    hr = ISpObjectToken_SetId( token, NULL, NULL, FALSE );
+    todo_wine ok( hr == E_POINTER, "got %08x\n", hr );
+    hr = ISpObjectToken_SetId( token, L"bogus", NULL, FALSE );
+    todo_wine ok( hr == E_POINTER, "got %08x\n", hr );
+
+    hr = ISpObjectToken_SetId( token, NULL, L"bogus", FALSE );
+    todo_wine ok( hr == SPERR_NOT_FOUND, "got %08x\n", hr );
+    hr = ISpObjectToken_SetId( token, NULL, L"HKEY_LOCAL_MACHINE\\SOFTWARE\\winetest bogus", FALSE );
+    todo_wine ok( hr == SPERR_NOT_FOUND, "got %08x\n", hr );
+
+    /* SetId succeeds even if the key is invalid, but exists */
+    hr = ISpObjectToken_SetId( token, NULL, L"HKEY_LOCAL_MACHINE\\SOFTWARE", FALSE );
+    todo_wine ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = ISpObjectToken_SetId( token, NULL, NULL, FALSE );
+    todo_wine ok( hr == SPERR_ALREADY_INITIALIZED, "got %08x\n", hr );
+    hr = ISpObjectToken_SetId( token, NULL, L"bogus", FALSE );
+    todo_wine ok( hr == SPERR_ALREADY_INITIALIZED, "got %08x\n", hr );
+
+    hr = ISpObjectToken_GetId( token, NULL );
+    todo_wine ok( hr == E_POINTER, "got %08x\n", hr );
+
+    hr = ISpObjectToken_GetCategory( token, NULL );
+    todo_wine ok( hr == E_POINTER, "got %08x\n", hr );
+
+    tempW = NULL;
+    hr = ISpObjectToken_GetId( token, &tempW );
+    todo_wine ok( hr == S_OK, "got %08x\n", hr );
+    todo_wine ok( tempW != NULL, "got %p\n", tempW );
+    if (tempW) {
+        ok( !wcscmp(tempW, L"HKEY_LOCAL_MACHINE\\SOFTWARE"), "got %s\n",
+            wine_dbgstr_w(tempW) );
+        CoTaskMemFree( tempW );
+    }
+
+    cat = (LPVOID)0xdeadbeef;
+    hr = ISpObjectToken_GetCategory( token, &cat );
+    todo_wine ok( hr == SPERR_INVALID_REGISTRY_KEY, "got %08x\n", hr );
+    ok( cat == (LPVOID)0xdeadbeef, "got %p\n", cat );
+
+    /* get the default token id for SPCAT_AUDIOOUT */
+    hr = CoCreateInstance( &CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER,
+                           &IID_ISpObjectTokenCategory, (void **)&cat );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = ISpObjectTokenCategory_SetId( cat, SPCAT_AUDIOOUT, FALSE );
+    if (hr == SPERR_NOT_FOUND) {
+        skip( "AudioOutput category not found for GetDefaultTokenId\n" );
+        return;
+    }
+    ok( hr == S_OK, "got %08x\n", hr );
+    token_id = (LPWSTR)0xdeadbeef;
+    hr = ISpObjectTokenCategory_GetDefaultTokenId( cat, &token_id );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( token_id != (LPWSTR)0xdeadbeef && token_id != NULL, "got %p\n", token_id );
+    ISpObjectTokenCategory_Release( cat );
+
+    /* recreate token in order to SetId again */
+    ISpObjectToken_Release( token );
+    hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER,
+                           &IID_ISpObjectToken, (void **)&token );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    /* NULL appears to auto-detect the category */
+    hr = ISpObjectToken_SetId( token, NULL, token_id, FALSE );
+    todo_wine ok( hr == S_OK, "got %08x\n", hr );
+
+    tempW = NULL;
+    hr = ISpObjectToken_GetId( token, &tempW );
+    todo_wine ok( hr == S_OK, "got %08x\n", hr );
+    todo_wine ok( tempW != NULL, "got %p\n", tempW );
+    if (tempW) {
+        ok( !wcscmp(tempW, token_id), "got %s\n", wine_dbgstr_w(tempW) );
+        CoTaskMemFree( tempW );
+    }
+
+    cat = (LPVOID)0xdeadbeef;
+    hr = ISpObjectToken_GetCategory( token, &cat );
+    todo_wine ok( hr == S_OK, "got %08x\n", hr );
+    todo_wine ok( cat != (LPVOID)0xdeadbeef, "got %p\n", cat );
+    if (cat != (LPVOID)0xdeadbeef) {
+        tempW = NULL;
+        hr = ISpObjectTokenCategory_GetId( cat, &tempW );
+        todo_wine ok( hr == S_OK, "got %08x\n", hr );
+        todo_wine ok( tempW != NULL, "got %p\n", tempW );
+        if (tempW) {
+            ok( !wcscmp(tempW, SPCAT_AUDIOOUT), "got %s\n", wine_dbgstr_w(tempW) );
+            CoTaskMemFree( tempW );
+        }
+
+        /* not freed by ISpObjectToken_Release */
+        ISpObjectTokenCategory_Release( cat );
+    }
+
+    ISpObjectToken_Release( token );
+}
+
 START_TEST(token)
 {
     CoInitialize( NULL );
@@ -181,5 +304,6 @@ START_TEST(token)
     test_token_category();
     test_token_enum();
     test_default_token_id();
+    test_object_token();
     CoUninitialize();
 }
diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c
index 21cd958282f..f7a00d73f02 100644
--- a/dlls/sapi/token.c
+++ b/dlls/sapi/token.c
@@ -776,3 +776,279 @@ HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj )
     ISpObjectTokenEnumBuilder_Release( &This->ISpObjectTokenEnumBuilder_iface );
     return hr;
 }
+
+struct object_token
+{
+    ISpObjectToken ISpObjectToken_iface;
+    LONG ref;
+};
+
+static struct object_token *impl_from_ISpObjectToken( ISpObjectToken *iface )
+{
+    return CONTAINING_RECORD( iface, struct object_token, ISpObjectToken_iface );
+}
+
+static HRESULT WINAPI token_QueryInterface( ISpObjectToken *iface,
+                                            REFIID iid, void **obj )
+{
+    struct object_token *This = impl_from_ISpObjectToken( iface );
+
+    TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
+
+    if (IsEqualIID( iid, &IID_IUnknown ) ||
+        IsEqualIID( iid, &IID_ISpDataKey ) ||
+        IsEqualIID( iid, &IID_ISpObjectToken ))
+    {
+        ISpObjectToken_AddRef( iface );
+        *obj = iface;
+        return S_OK;
+    }
+
+    FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI token_AddRef( ISpObjectToken *iface )
+{
+    struct object_token *This = impl_from_ISpObjectToken( iface );
+    ULONG ref = InterlockedIncrement( &This->ref );
+
+    TRACE( "(%p) ref = %u\n", This, ref );
+    return ref;
+}
+
+static ULONG WINAPI token_Release( ISpObjectToken *iface )
+{
+    struct object_token *This = impl_from_ISpObjectToken( iface );
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE( "(%p) ref = %u\n", This, ref );
+
+    if (!ref)
+    {
+        heap_free( This );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI token_SetData( ISpObjectToken *iface,
+                                     LPCWSTR name, ULONG size,
+                                     const BYTE *data )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_GetData( ISpObjectToken *iface,
+                                     LPCWSTR name, ULONG *size,
+                                     BYTE *data )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_SetStringValue( ISpObjectToken *iface,
+                                            LPCWSTR name, LPCWSTR value )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_GetStringValue( ISpObjectToken *iface,
+                                            LPCWSTR name, LPWSTR *value )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_SetDWORD( ISpObjectToken *iface,
+                                      LPCWSTR name, DWORD value )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_GetDWORD( ISpObjectToken *iface,
+                                      LPCWSTR name, DWORD *pdwValue )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_OpenKey( ISpObjectToken *iface,
+                                     LPCWSTR name, ISpDataKey **sub_key )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_CreateKey( ISpObjectToken *iface,
+                                       LPCWSTR name, ISpDataKey **sub_key )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_DeleteKey( ISpObjectToken *iface,
+                                       LPCWSTR name )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_DeleteValue( ISpObjectToken *iface,
+                                         LPCWSTR name )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_EnumKeys( ISpObjectToken *iface,
+                                      ULONG index, LPWSTR *sub_key )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_EnumValues( ISpObjectToken *iface,
+                                        ULONG index, LPWSTR *value )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_SetId( ISpObjectToken *iface,
+                                   LPCWSTR category_id, LPCWSTR token_id,
+                                   BOOL create )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_GetId( ISpObjectToken *iface,
+                                   LPWSTR *token_id )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_GetCategory( ISpObjectToken *iface,
+                                         ISpObjectTokenCategory **category )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_CreateInstance( ISpObjectToken *iface,
+                                            IUnknown *outer,
+                                            DWORD class_context,
+                                            REFIID riid,
+                                            void **object )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_GetStorageFileName( ISpObjectToken *iface,
+                                                REFCLSID caller,
+                                                LPCWSTR key_name,
+                                                LPCWSTR filename,
+                                                ULONG folder,
+                                                LPWSTR *filepath )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_RemoveStorageFileName( ISpObjectToken *iface,
+                                                   REFCLSID caller,
+                                                   LPCWSTR key_name,
+                                                   BOOL delete_file )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_Remove( ISpObjectToken *iface,
+                                    REFCLSID caller )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_IsUISupported( ISpObjectToken *iface,
+                                           LPCWSTR ui_type,
+                                           void *extra_data,
+                                           ULONG extra_data_size,
+                                           IUnknown *object,
+                                           BOOL *supported )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_DisplayUI( ISpObjectToken *iface,
+                                       HWND parent,
+                                       LPCWSTR title,
+                                       LPCWSTR ui_type,
+                                       void *extra_data,
+                                       ULONG extra_data_size,
+                                       IUnknown *object )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_MatchesAttributes( ISpObjectToken *iface,
+                                               LPCWSTR attributes,
+                                               BOOL *matches )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+const struct ISpObjectTokenVtbl token_vtbl =
+{
+    token_QueryInterface,
+    token_AddRef,
+    token_Release,
+    token_SetData,
+    token_GetData,
+    token_SetStringValue,
+    token_GetStringValue,
+    token_SetDWORD,
+    token_GetDWORD,
+    token_OpenKey,
+    token_CreateKey,
+    token_DeleteKey,
+    token_DeleteValue,
+    token_EnumKeys,
+    token_EnumValues,
+    token_SetId,
+    token_GetId,
+    token_GetCategory,
+    token_CreateInstance,
+    token_GetStorageFileName,
+    token_RemoveStorageFileName,
+    token_Remove,
+    token_IsUISupported,
+    token_DisplayUI,
+    token_MatchesAttributes
+};
+
+HRESULT token_create( IUnknown *outer, REFIID iid, void **obj )
+{
+    struct object_token *This = heap_alloc( sizeof(*This) );
+    HRESULT hr;
+
+    if (!This) return E_OUTOFMEMORY;
+    This->ISpObjectToken_iface.lpVtbl = &token_vtbl;
+    This->ref = 1;
+
+    hr = ISpObjectToken_QueryInterface( &This->ISpObjectToken_iface, iid, obj );
+
+    ISpObjectToken_Release( &This->ISpObjectToken_iface );
+    return hr;
+}
diff --git a/include/sapi.idl b/include/sapi.idl
index 9e6ba5be5ea..0a7a034cace 100644
--- a/include/sapi.idl
+++ b/include/sapi.idl
@@ -1064,6 +1064,19 @@ library SpeechLib
         interface ISpObjectTokenCategory;
     }

+    [
+        uuid(ef411752-3736-4cb4-9c8c-8ef4ccb58efe),
+        helpstring("Object Token"),
+        progid("SAPI.SpObjectToken.1"),
+        vi_progid("SAPI.SpObjectToken"),
+        threading(both)
+    ]
+    coclass SpObjectToken
+    {
+        interface ISpObjectToken;
+        [default] interface ISpDataKey;
+    }
+
     [
         uuid(3bee4890-4fe9-4a37-8c1e-5e7e12791c1f)
     ]
--
2.28.0





More information about the wine-devel mailing list