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

Myah Caron qsniyg at protonmail.com
Wed Sep 16 01:22:59 CDT 2020


Signed-off-by: Myah Caron <qsniyg at protonmail.com>
---
v2:
 - Fix test under Windows server (skip was for the wrong function)
 - Fix GetId test failure (see notes below).
 - Remove GetId implementation from patchset.

The GetId test failure did not occur on my Windows 10 installation, as GetDefaultTokenId had already
provided {0.0.0.00000000}.{guid}. Under my installation, the GUID refers to one of two devices in
HLKM\Software\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render. My guess is that the audio
device is being instantiated somehow.

This would be an interesting area for further research, but for the moment I'd prefer to focus on
fixing the bug instead. Since the required functions are SetId and CreateInstance, it doesn't appear
that a correct ID is required for stubbing enough of either of these, so I don't believe it matters
for this patchset.

Regarding the test itself, I've cut the comparison in order to only check up to the length of the
result of GetDefaultTokenId. It's admittedly a stop-gap measure, the test could also be removed.

Regarding the debian test failures, I believe it's because the classes are not registered, ref. the
comment at the top of sapi_classes.idl. It works on my end, after running `wineboot -u`.


Original notes below:

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    | 125 +++++++++++++++++
 dlls/sapi/token.c          | 276 +++++++++++++++++++++++++++++++++++++
 include/sapi.idl           |  13 ++
 6 files changed, 431 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..887539778a9 100644
--- a/dlls/sapi/tests/token.c
+++ b/dlls/sapi/tests/token.c
@@ -174,6 +174,130 @@ 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 );
+    ok( hr == S_OK, "got %08x\n", hr );
+    token_id = (LPWSTR)0xdeadbeef;
+    hr = ISpObjectTokenCategory_GetDefaultTokenId( cat, &token_id );
+    if (hr == SPERR_NOT_FOUND) {
+        skip( "AudioOutput category not found for GetDefaultTokenId\n" );
+        return;
+    }
+    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( !wcsncmp(tempW, token_id, wcslen(token_id)),
+            "got %s (expected %s)\n", wine_dbgstr_w(tempW), wine_dbgstr_w(token_id) );
+        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 +305,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