-- v2: sapi: Implement ISpObjectToken::CreateInstance. sapi: Implement ISpObjectToken::Set/GetStringValue. sapi: Use ISpRegDataKey in object_token. sapi: Implement ISpRegDataKey::OpenKey. sapi: Ignore read_only in ISpRegDataKey::SetKey. sapi: Implement ISpRegDataKey::SetStringValue.
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/token.c | 14 +++++++++++++- dlls/sapi/token.c | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 958c50359f5..792b65a6366 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -33,7 +33,7 @@ static void test_data_key(void) HRESULT hr; HKEY key; LONG res; - WCHAR *value; + WCHAR *value = NULL;
hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, &IID_ISpRegDataKey, (void **)&data_key ); @@ -49,6 +49,9 @@ static void test_data_key(void) hr = ISpRegDataKey_GetStringValue( data_key, L"Voice", &value ); ok( hr == E_HANDLE, "got %08lx\n", hr );
+ hr = ISpRegDataKey_SetStringValue( data_key, L"Voice", L"Test" ); + ok( hr == E_HANDLE, "got %08lx\n", hr ); + hr = ISpRegDataKey_SetKey( data_key, key, FALSE ); ok( hr == S_OK, "got %08lx\n", hr ); hr = ISpRegDataKey_SetKey( data_key, key, FALSE ); @@ -60,6 +63,14 @@ static void test_data_key(void) hr = ISpRegDataKey_GetStringValue( data_key, L"", &value ); ok( hr == SPERR_NOT_FOUND, "got %08lx\n", hr );
+ hr = ISpRegDataKey_SetStringValue( data_key, L"Voice", L"Test" ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpRegDataKey_GetStringValue( data_key, L"Voice", &value ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( !wcscmp( value, L"Test" ), "got %s\n", wine_dbgstr_w(value) ); + CoTaskMemFree( value ); + hr = ISpRegDataKey_CreateKey( data_key, L"Testing", &sub ); ok( hr == S_OK, "got %08lx\n", hr ); ISpDataKey_Release(sub); @@ -361,6 +372,7 @@ static void test_object_token(void) START_TEST(token) { CoInitialize( NULL ); + RegDeleteTreeA( HKEY_CURRENT_USER, "Software\Winetest\sapi" ); test_data_key(); test_token_category(); test_token_enum(); diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 385555a4cef..6c862bb030c 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -124,8 +124,18 @@ static HRESULT WINAPI data_key_GetData( ISpRegDataKey *iface, LPCWSTR name, static HRESULT WINAPI data_key_SetStringValue( ISpRegDataKey *iface, LPCWSTR name, LPCWSTR value ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct data_key *This = impl_from_ISpRegDataKey( iface ); + DWORD ret, size; + + TRACE( "%p, %s, %s\n", This, debugstr_w(name), debugstr_w(value) ); + + if (!This->key) + return E_HANDLE; + + size = (wcslen(value) + 1) * sizeof(WCHAR); + ret = RegSetValueExW( This->key, name, 0, REG_SZ, (BYTE *)value, size ); + + return HRESULT_FROM_WIN32(ret); }
static HRESULT WINAPI data_key_GetStringValue( ISpRegDataKey *iface,
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/token.c | 24 ++++++++++++++++++++++++ dlls/sapi/token.c | 4 +--- 2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 792b65a6366..603e2143ff9 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -76,6 +76,30 @@ static void test_data_key(void) ISpDataKey_Release(sub);
ISpRegDataKey_Release( data_key ); + + hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpRegDataKey, (void **)&data_key ); + ok( hr == S_OK, "got %08lx\n", hr ); + + res = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\Winetest\sapi", 0, KEY_ALL_ACCESS, &key ); + ok( res == ERROR_SUCCESS, "got %ld\n", res ); + + hr = ISpRegDataKey_SetKey( data_key, key, TRUE ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpRegDataKey_SetStringValue( data_key, L"Voice2", L"Test2" ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpRegDataKey_GetStringValue( data_key, L"Voice2", &value ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( !wcscmp( value, L"Test2" ), "got %s\n", wine_dbgstr_w(value) ); + CoTaskMemFree( value ); + + hr = ISpRegDataKey_CreateKey( data_key, L"Testing2", &sub ); + ok( hr == S_OK, "got %08lx\n", hr ); + ISpDataKey_Release(sub); + + ISpRegDataKey_Release( data_key ); }
static void test_token_category(void) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 6c862bb030c..74ef6884fbc 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -40,7 +40,6 @@ struct data_key LONG ref;
HKEY key; - BOOL read_only; };
static struct data_key *impl_from_ISpRegDataKey( ISpRegDataKey *iface ) @@ -253,8 +252,8 @@ static HRESULT WINAPI data_key_SetKey( ISpRegDataKey *iface,
if (This->key) return SPERR_ALREADY_INITIALIZED;
+ /* read_only is ignored in Windows implementations. */ This->key = key; - This->read_only = read_only; return S_OK; }
@@ -287,7 +286,6 @@ HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) This->ISpRegDataKey_iface.lpVtbl = &data_key_vtbl; This->ref = 1; This->key = NULL; - This->read_only = FALSE;
hr = ISpRegDataKey_QueryInterface( &This->ISpRegDataKey_iface, iid, obj );
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/token.c | 7 +++++++ dlls/sapi/token.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 603e2143ff9..2602b043980 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -71,10 +71,17 @@ static void test_data_key(void) ok( !wcscmp( value, L"Test" ), "got %s\n", wine_dbgstr_w(value) ); CoTaskMemFree( value );
+ hr = ISpRegDataKey_OpenKey( data_key, L"Testing", &sub ); + ok( hr == SPERR_NOT_FOUND, "got %08lx\n", hr ); + hr = ISpRegDataKey_CreateKey( data_key, L"Testing", &sub ); ok( hr == S_OK, "got %08lx\n", hr ); ISpDataKey_Release(sub);
+ hr = ISpRegDataKey_OpenKey( data_key, L"Testing", &sub ); + ok( hr == S_OK, "got %08lx\n", hr ); + ISpDataKey_Release(sub); + ISpRegDataKey_Release( data_key );
hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 74ef6884fbc..7bd28dca31c 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -186,8 +186,37 @@ static HRESULT WINAPI data_key_GetDWORD( ISpRegDataKey *iface, static HRESULT WINAPI data_key_OpenKey( ISpRegDataKey *iface, LPCWSTR name, ISpDataKey **sub_key ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct data_key *This = impl_from_ISpRegDataKey( iface ); + ISpRegDataKey *spregkey; + HRESULT hr; + HKEY key; + LONG ret; + + TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key ); + + ret = RegOpenKeyExW( This->key, name, 0, KEY_ALL_ACCESS, &key ); + if (ret != ERROR_SUCCESS) + return SPERR_NOT_FOUND; + + hr = data_key_create( NULL, &IID_ISpRegDataKey, (void**)&spregkey ); + if (FAILED(hr)) + { + RegCloseKey( key ); + return hr; + } + + hr = ISpRegDataKey_SetKey( spregkey, key, FALSE ); + if (FAILED(hr)) + { + RegCloseKey( key ); + ISpRegDataKey_Release( spregkey ); + return hr; + } + + hr = ISpRegDataKey_QueryInterface( spregkey, &IID_ISpDataKey, (void**)sub_key ); + ISpRegDataKey_Release( spregkey ); + + return hr; }
static HRESULT WINAPI data_key_CreateKey( ISpRegDataKey *iface,
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/token.c | 102 ++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 45 deletions(-)
diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 7bd28dca31c..0465819de56 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -52,7 +52,7 @@ struct object_token ISpObjectToken ISpObjectToken_iface; LONG ref;
- HKEY token_key; + ISpRegDataKey *data_key; WCHAR *token_id; };
@@ -496,6 +496,23 @@ static HRESULT parse_cat_id( const WCHAR *str, HKEY *root, const WCHAR **sub_key return S_FALSE; }
+static HRESULT WINAPI create_data_key_with_hkey( HKEY key, ISpRegDataKey **data_key ) +{ + HRESULT hr; + + if (FAILED(hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpRegDataKey, (void **)data_key ) )) + return hr; + + if (FAILED(hr = ISpRegDataKey_SetKey( *data_key, key, TRUE ))) + { + ISpRegDataKey_Release( *data_key ); + *data_key = NULL; + } + + return hr; +} + static HRESULT WINAPI token_category_SetId( ISpObjectTokenCategory *iface, LPCWSTR id, BOOL create ) { @@ -518,17 +535,12 @@ static HRESULT WINAPI token_category_SetId( ISpObjectTokenCategory *iface, res = RegOpenKeyExW( root, subkey, 0, KEY_ALL_ACCESS, &key ); if (res) return SPERR_INVALID_REGISTRY_KEY;
- hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_ALL, - &IID_ISpRegDataKey, (void **)&This->data_key ); - if (FAILED(hr)) goto fail; - - hr = ISpRegDataKey_SetKey( This->data_key, key, FALSE ); - if (FAILED(hr)) goto fail; - - return hr; + if (FAILED(hr = create_data_key_with_hkey( key, &This->data_key ))) + { + RegCloseKey( key ); + return hr; + }
-fail: - RegCloseKey( key ); return hr; }
@@ -748,6 +760,7 @@ static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface, WCHAR *subkey_name; HKEY sub_key; DWORD size; + ISpRegDataKey *data_key;
TRACE( "(%p)->(%lu %p %p)\n", This, num, tokens, fetched );
@@ -777,15 +790,24 @@ static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface, return E_FAIL; }
+ hr = create_data_key_with_hkey( sub_key, &data_key ); + if (FAILED(hr)) + { + free( subkey_name ); + RegCloseKey( sub_key ); + return hr; + } + hr = token_create( NULL, &IID_ISpObjectToken, (void**)tokens ); if (FAILED(hr)) { free( subkey_name ); + ISpRegDataKey_Release( data_key ); return hr; }
object = impl_from_ISpObjectToken( *tokens ); - object->token_key = sub_key; + object->data_key = data_key; object->token_id = subkey_name;
if (fetched) *fetched = 1; @@ -823,6 +845,7 @@ static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface, DWORD size; LONG ret; HKEY key; + ISpRegDataKey *data_key;
TRACE( "%p, %lu, %p\n", This, index, token );
@@ -849,15 +872,24 @@ static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface, return HRESULT_FROM_WIN32(ret); }
+ hr = create_data_key_with_hkey( key, &data_key ); + if (FAILED(hr)) + { + free( subkey ); + RegCloseKey( key ); + return hr; + } + hr = token_create( NULL, &IID_ISpObjectToken, (void**)&subtoken ); if (FAILED(hr)) { free( subkey ); + ISpRegDataKey_Release( data_key ); return hr; }
object = impl_from_ISpObjectToken( subtoken ); - object->token_key = key; + object->data_key = data_key; object->token_id = subkey;
*token = subtoken; @@ -1014,7 +1046,7 @@ static ULONG WINAPI token_Release( ISpObjectToken *iface )
if (!ref) { - if (This->token_key) RegCloseKey( This->token_key ); + if (This->data_key) ISpRegDataKey_Release( This->data_key ); free( This->token_id ); free( This ); } @@ -1070,36 +1102,10 @@ static HRESULT WINAPI token_OpenKey( ISpObjectToken *iface, LPCWSTR name, ISpDataKey **sub_key ) { struct object_token *This = impl_from_ISpObjectToken( iface ); - ISpRegDataKey *spregkey; - HRESULT hr; - HKEY key; - LONG ret;
TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key );
- ret = RegOpenKeyExW (This->token_key, name, 0, KEY_ALL_ACCESS, &key); - if (ret != ERROR_SUCCESS) - return SPERR_NOT_FOUND; - - hr = data_key_create(NULL, &IID_ISpRegDataKey, (void**)&spregkey); - if (FAILED(hr)) - { - RegCloseKey(key); - return hr; - } - - hr = ISpRegDataKey_SetKey(spregkey, key, FALSE); - if (FAILED(hr)) - { - RegCloseKey(key); - ISpRegDataKey_Release(spregkey); - return hr; - } - - hr = ISpRegDataKey_QueryInterface(spregkey, &IID_ISpDataKey, (void**)sub_key); - ISpRegDataKey_Release(spregkey); - - return hr; + return ISpRegDataKey_OpenKey( This->data_key, name, sub_key ); }
static HRESULT WINAPI token_CreateKey( ISpObjectToken *iface, @@ -1150,7 +1156,7 @@ static HRESULT WINAPI token_SetId( ISpObjectToken *iface, FIXME( "(%p)->(%s %s %d): semi-stub\n", This, debugstr_w( category_id ), debugstr_w(token_id), create );
- if (This->token_key) return SPERR_ALREADY_INITIALIZED; + if (This->data_key) return SPERR_ALREADY_INITIALIZED;
if (!token_id) return E_POINTER;
@@ -1163,7 +1169,13 @@ static HRESULT WINAPI token_SetId( ISpObjectToken *iface, res = RegOpenKeyExW( root, subkey, 0, KEY_ALL_ACCESS, &key ); if (res) return SPERR_NOT_FOUND;
- This->token_key = key; + hr = create_data_key_with_hkey( key, &This->data_key ); + if (FAILED(hr)) + { + RegCloseKey( key ); + return hr; + } + This->token_id = wcsdup(token_id);
return S_OK; @@ -1176,7 +1188,7 @@ static HRESULT WINAPI token_GetId( ISpObjectToken *iface,
TRACE( "%p, %p\n", This, token_id);
- if (!This->token_key) + if (!This->data_key) return SPERR_UNINITIALIZED;
if (!token_id) @@ -1309,7 +1321,7 @@ HRESULT token_create( IUnknown *outer, REFIID iid, void **obj ) This->ISpObjectToken_iface.lpVtbl = &token_vtbl; This->ref = 1;
- This->token_key = NULL; + This->data_key = NULL; This->token_id = NULL;
hr = ISpObjectToken_QueryInterface( &This->ISpObjectToken_iface, iid, obj );
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/token.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 0465819de56..6f8d677c9d0 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1073,15 +1073,21 @@ static HRESULT WINAPI token_GetData( ISpObjectToken *iface, static HRESULT WINAPI token_SetStringValue( ISpObjectToken *iface, LPCWSTR name, LPCWSTR value ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct object_token *This = impl_from_ISpObjectToken( iface ); + + TRACE( "%p, %s, %s\n", This, debugstr_w(name), debugstr_w(value) ); + + return ISpRegDataKey_SetStringValue( This->data_key, name, value ); }
static HRESULT WINAPI token_GetStringValue( ISpObjectToken *iface, LPCWSTR name, LPWSTR *value ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct object_token *This = impl_from_ISpObjectToken( iface ); + + TRACE( "%p, %s, %p\n", This, debugstr_w(name), value ); + + return ISpRegDataKey_GetStringValue( This->data_key, name, value ); }
static HRESULT WINAPI token_SetDWORD( ISpObjectToken *iface,
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/token.c | 149 ++++++++++++++++++++++++++++++++++++++++ dlls/sapi/token.c | 35 +++++++++- 2 files changed, 182 insertions(+), 2 deletions(-)
diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 2602b043980..3629a86b126 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -268,13 +268,117 @@ static void tests_token_voices(void) IEnumSpObjectTokens_Release(tokens); }
+ +#define TESTCLASS_CLSID L"{67DD26B6-50BA-3297-253E-619346F177F8}" +static const GUID CLSID_TestClass = {0x67DD26B6,0x50BA,0x3297,{0x25,0x3E,0x61,0x93,0x46,0xF1,0x77,0xF8}}; + +static ISpObjectToken *test_class_token; + +static HRESULT WINAPI test_class_QueryInterface(ISpObjectWithToken *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID( riid, &IID_IUnknown ) || IsEqualGUID( riid, &IID_ISpObjectWithToken )) + { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_class_AddRef(ISpObjectWithToken *iface) +{ + return 2; +} + +static ULONG WINAPI test_class_Release(ISpObjectWithToken *iface) +{ + return 1; +} + +static HRESULT WINAPI test_class_SetObjectToken(ISpObjectWithToken *iface, ISpObjectToken *token) +{ + ok( token != NULL, "token == NULL\n" ); + test_class_token = token; + ISpObjectToken_AddRef(test_class_token); + return S_OK; +} + +static HRESULT WINAPI test_class_GetObjectToken(ISpObjectWithToken *iface, ISpObjectToken **token) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static const ISpObjectWithTokenVtbl test_class_vtbl = { + test_class_QueryInterface, + test_class_AddRef, + test_class_Release, + test_class_SetObjectToken, + test_class_GetObjectToken +}; + +static ISpObjectWithToken test_class = { &test_class_vtbl }; + +static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID( &IID_IUnknown, riid ) || IsEqualGUID( &IID_IClassFactory, riid )) + { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, + IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + ok( pUnkOuter == NULL, "pUnkOuter != NULL\n" ); + ok( IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", wine_dbgstr_guid(riid) ); + + *ppv = &test_class; + return S_OK; +} + +static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static const IClassFactoryVtbl ClassFactoryVtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + ClassFactory_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory test_class_cf = { &ClassFactoryVtbl }; + static void test_object_token(void) { + static const WCHAR test_token_id[] = L"HKEY_CURRENT_USER\Software\Winetest\sapi\TestToken"; + ISpObjectToken *token; ISpDataKey *sub_key; HRESULT hr; LPWSTR tempW, token_id; ISpObjectTokenCategory *cat; + DWORD regid; + IUnknown *obj;
hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, &IID_ISpObjectToken, (void **)&token ); @@ -397,6 +501,51 @@ static void test_object_token(void) ISpObjectTokenCategory_Release( cat ); }
+ hr = CoRegisterClassObject( &CLSID_TestClass, (IUnknown *)&test_class_cf, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id ); + ok( hr == S_OK, "got %08lx\n", hr ); + + ISpObjectToken_Release( token ); + hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectToken, (void **)&token ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpObjectToken_SetId( token, NULL, test_token_id, TRUE ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpObjectToken_SetStringValue( token, L"CLSID", TESTCLASS_CLSID ); + ok( hr == S_OK, "got %08lx\n", hr ); + + tempW = NULL; + hr = ISpObjectToken_GetStringValue( token, L"CLSID", &tempW ); + + ok( hr == S_OK, "got %08lx\n", hr ); + if ( tempW ) { + ok( !wcsncmp( tempW, TESTCLASS_CLSID, wcslen(TESTCLASS_CLSID) ), + "got %s (expected %s)\n", wine_dbgstr_w(tempW), wine_dbgstr_w(TESTCLASS_CLSID) ); + CoTaskMemFree( tempW ); + } + + test_class_token = NULL; + hr = ISpObjectToken_CreateInstance( token, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&obj ); + if ( hr == E_ACCESSDENIED ) { + win_skip( "ISpObjectToken_CreateInstance returned E_ACCESSDENIED\n" ); + return; + } + ok( hr == S_OK, "got %08lx\n", hr ); + ok( test_class_token != NULL, "test_class_token not set\n" ); + + tempW = NULL; + hr = ISpObjectToken_GetId( test_class_token, &tempW ); + ok( tempW != NULL, "got %p\n", tempW ); + if (tempW) { + ok( !wcsncmp(tempW, test_token_id, wcslen(test_token_id)), + "got %s (expected %s)\n", wine_dbgstr_w(tempW), wine_dbgstr_w(test_token_id) ); + CoTaskMemFree( tempW ); + } + + ISpObjectToken_Release( test_class_token ); + IUnknown_Release( obj ); ISpObjectToken_Release( token ); }
diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 6f8d677c9d0..6cc7ccd6d73 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1227,8 +1227,39 @@ static HRESULT WINAPI token_CreateInstance( ISpObjectToken *iface, REFIID riid, void **object ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + WCHAR *clsid_str; + CLSID clsid; + IUnknown *unk; + ISpObjectWithToken *obj_token_iface; + HRESULT hr; + + TRACE( "%p, %p, %#lx, %s, %p\n", iface, outer, class_context, debugstr_guid( riid ), object ); + + if (FAILED(hr = ISpObjectToken_GetStringValue( iface, L"CLSID", &clsid_str ))) + return hr; + + hr = CLSIDFromString( clsid_str, &clsid ); + CoTaskMemFree( clsid_str ); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = CoCreateInstance( &clsid, outer, class_context, &IID_IUnknown, (void **)&unk ))) + return hr; + + /* Call ISpObjectWithToken::SetObjectToken if the interface is available. */ + if (SUCCEEDED(IUnknown_QueryInterface( unk, &IID_ISpObjectWithToken, (void **)&obj_token_iface ))) + { + hr = ISpObjectWithToken_SetObjectToken( obj_token_iface, iface ); + ISpObjectWithToken_Release( obj_token_iface ); + if (FAILED(hr)) + goto done; + } + + hr = IUnknown_QueryInterface( unk, riid, object ); + +done: + IUnknown_Release( unk ); + return hr; }
static HRESULT WINAPI token_GetStorageFileName( ISpObjectToken *iface,
On Thu May 4 12:15:22 2023 +0000, Giovanni Mascellani wrote:
Apparently a data key can be set as read-only. Maybe this should be taken into account here (it shouldn't be too hard to test for that).
It actually seems that the Windows implementations of SetKey completely ignore `read_only`.
Or is it intentional that `CreateInstance()` should still succeed when creating something that doesn't implement `ISpObjectWithToken`?
Yes, `IspObjectToken::SetObjectToken()` should only be called if it is available.
Also, it seems that in the happy path you call `QueryInstance()` twice and `Release()` only once, which would mean that you return a pointer with refcount 2. I don't think that's intended?
Good catch, fixed.
This merge request was approved by Giovanni Mascellani.
This merge request was approved by Huw Davies.