2 * Speech API (SAPI) token implementation.
4 * Copyright (C) 2017 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/debug.h"
34 #include "sapi_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(sapi
);
40 ISpRegDataKey ISpRegDataKey_iface
;
46 static struct data_key
*impl_from_ISpRegDataKey( ISpRegDataKey
*iface
)
48 return CONTAINING_RECORD( iface
, struct data_key
, ISpRegDataKey_iface
);
53 ISpObjectToken ISpObjectToken_iface
;
56 ISpRegDataKey
*data_key
;
60 static struct object_token
*impl_from_ISpObjectToken( ISpObjectToken
*iface
)
62 return CONTAINING_RECORD( iface
, struct object_token
, ISpObjectToken_iface
);
65 static HRESULT WINAPI
data_key_QueryInterface( ISpRegDataKey
*iface
, REFIID iid
, void **obj
)
67 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
69 TRACE( "(%p)->(%s %p)\n", This
, debugstr_guid( iid
), obj
);
71 if (IsEqualIID( iid
, &IID_IUnknown
) ||
72 IsEqualIID( iid
, &IID_ISpDataKey
) ||
73 IsEqualIID( iid
, &IID_ISpRegDataKey
))
75 ISpRegDataKey_AddRef( iface
);
80 FIXME( "interface %s not implemented\n", debugstr_guid( iid
) );
85 static ULONG WINAPI
data_key_AddRef( ISpRegDataKey
*iface
)
87 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
88 ULONG ref
= InterlockedIncrement( &This
->ref
);
90 TRACE( "(%p) ref = %lu\n", This
, ref
);
94 static ULONG WINAPI
data_key_Release( ISpRegDataKey
*iface
)
96 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
97 ULONG ref
= InterlockedDecrement(&This
->ref
);
99 TRACE( "(%p) ref = %lu\n", This
, ref
);
103 if (This
->key
) RegCloseKey( This
->key
);
110 static HRESULT WINAPI
data_key_SetData( ISpRegDataKey
*iface
, LPCWSTR name
,
111 ULONG size
, const BYTE
*data
)
117 static HRESULT WINAPI
data_key_GetData( ISpRegDataKey
*iface
, LPCWSTR name
,
118 ULONG
*size
, BYTE
*data
)
124 static HRESULT WINAPI
data_key_SetStringValue( ISpRegDataKey
*iface
,
125 LPCWSTR name
, LPCWSTR value
)
127 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
130 TRACE( "%p, %s, %s\n", This
, debugstr_w(name
), debugstr_w(value
) );
135 size
= (wcslen(value
) + 1) * sizeof(WCHAR
);
136 ret
= RegSetValueExW( This
->key
, name
, 0, REG_SZ
, (BYTE
*)value
, size
);
138 return HRESULT_FROM_WIN32(ret
);
141 static HRESULT WINAPI
data_key_GetStringValue( ISpRegDataKey
*iface
,
142 LPCWSTR name
, LPWSTR
*value
)
144 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
148 TRACE( "%p, %s, %p\n", This
, debugstr_w(name
), value
);
154 ret
= RegGetValueW( This
->key
, NULL
, name
, RRF_RT_REG_SZ
, NULL
, NULL
, &size
);
155 if (ret
!= ERROR_SUCCESS
)
156 return SPERR_NOT_FOUND
;
158 content
= CoTaskMemAlloc(size
);
160 return E_OUTOFMEMORY
;
162 ret
= RegGetValueW( This
->key
, NULL
, name
, RRF_RT_REG_SZ
, NULL
, content
, &size
);
163 if (ret
!= ERROR_SUCCESS
)
165 CoTaskMemFree(content
);
166 return HRESULT_FROM_WIN32(ret
);
173 static HRESULT WINAPI
data_key_SetDWORD( ISpRegDataKey
*iface
,
174 LPCWSTR name
, DWORD value
)
180 static HRESULT WINAPI
data_key_GetDWORD( ISpRegDataKey
*iface
,
181 LPCWSTR name
, DWORD
*pdwValue
)
187 static HRESULT WINAPI
data_key_OpenKey( ISpRegDataKey
*iface
,
188 LPCWSTR name
, ISpDataKey
**sub_key
)
190 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
191 ISpRegDataKey
*spregkey
;
196 TRACE( "%p, %s, %p\n", This
, debugstr_w(name
), sub_key
);
198 ret
= RegOpenKeyExW( This
->key
, name
, 0, KEY_ALL_ACCESS
, &key
);
199 if (ret
!= ERROR_SUCCESS
)
200 return SPERR_NOT_FOUND
;
202 hr
= data_key_create( NULL
, &IID_ISpRegDataKey
, (void**)&spregkey
);
209 hr
= ISpRegDataKey_SetKey( spregkey
, key
, FALSE
);
213 ISpRegDataKey_Release( spregkey
);
217 hr
= ISpRegDataKey_QueryInterface( spregkey
, &IID_ISpDataKey
, (void**)sub_key
);
218 ISpRegDataKey_Release( spregkey
);
223 static HRESULT WINAPI
data_key_CreateKey( ISpRegDataKey
*iface
,
224 LPCWSTR name
, ISpDataKey
**sub_key
)
226 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
227 ISpRegDataKey
*spregkey
;
232 TRACE( "%p, %s, %p\n", This
, debugstr_w(name
), sub_key
);
234 res
= RegCreateKeyExW( This
->key
, name
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
235 if (res
!= ERROR_SUCCESS
)
236 return HRESULT_FROM_WIN32(res
);
238 hr
= data_key_create(NULL
, &IID_ISpRegDataKey
, (void**)&spregkey
);
241 hr
= ISpRegDataKey_SetKey(spregkey
, key
, FALSE
);
243 hr
= ISpRegDataKey_QueryInterface(spregkey
, &IID_ISpDataKey
, (void**)sub_key
);
244 ISpRegDataKey_Release(spregkey
);
250 static HRESULT WINAPI
data_key_DeleteKey( ISpRegDataKey
*iface
, LPCWSTR name
)
256 static HRESULT WINAPI
data_key_DeleteValue( ISpRegDataKey
*iface
, LPCWSTR name
)
262 static HRESULT WINAPI
data_key_EnumKeys( ISpRegDataKey
*iface
,
263 ULONG index
, LPWSTR
*sub_key
)
269 static HRESULT WINAPI
data_key_EnumValues( ISpRegDataKey
*iface
,
270 ULONG index
, LPWSTR
*value
)
276 static HRESULT WINAPI
data_key_SetKey( ISpRegDataKey
*iface
,
277 HKEY key
, BOOL read_only
)
279 struct data_key
*This
= impl_from_ISpRegDataKey( iface
);
281 TRACE( "(%p)->(%p %d)\n", This
, key
, read_only
);
283 if (This
->key
) return SPERR_ALREADY_INITIALIZED
;
285 /* read_only is ignored in Windows implementations. */
290 const struct ISpRegDataKeyVtbl data_key_vtbl
=
292 data_key_QueryInterface
,
297 data_key_SetStringValue
,
298 data_key_GetStringValue
,
304 data_key_DeleteValue
,
310 HRESULT
data_key_create( IUnknown
*outer
, REFIID iid
, void **obj
)
312 struct data_key
*This
= malloc( sizeof(*This
) );
315 if (!This
) return E_OUTOFMEMORY
;
316 This
->ISpRegDataKey_iface
.lpVtbl
= &data_key_vtbl
;
320 hr
= ISpRegDataKey_QueryInterface( &This
->ISpRegDataKey_iface
, iid
, obj
);
322 ISpRegDataKey_Release( &This
->ISpRegDataKey_iface
);
326 struct token_category
328 ISpObjectTokenCategory ISpObjectTokenCategory_iface
;
331 ISpRegDataKey
*data_key
;
335 static struct token_category
*impl_from_ISpObjectTokenCategory( ISpObjectTokenCategory
*iface
)
337 return CONTAINING_RECORD( iface
, struct token_category
, ISpObjectTokenCategory_iface
);
340 static HRESULT WINAPI
token_category_QueryInterface( ISpObjectTokenCategory
*iface
,
341 REFIID iid
, void **obj
)
343 struct token_category
*This
= impl_from_ISpObjectTokenCategory( iface
);
345 TRACE( "(%p)->(%s %p)\n", This
, debugstr_guid( iid
), obj
);
347 if (IsEqualIID( iid
, &IID_IUnknown
) ||
348 IsEqualIID( iid
, &IID_ISpDataKey
) ||
349 IsEqualIID( iid
, &IID_ISpObjectTokenCategory
))
351 ISpObjectTokenCategory_AddRef( iface
);
356 FIXME( "interface %s not implemented\n", debugstr_guid( iid
) );
358 return E_NOINTERFACE
;
361 static ULONG WINAPI
token_category_AddRef( ISpObjectTokenCategory
*iface
)
363 struct token_category
*This
= impl_from_ISpObjectTokenCategory( iface
);
364 ULONG ref
= InterlockedIncrement( &This
->ref
);
366 TRACE( "(%p) ref = %lu\n", This
, ref
);
370 static ULONG WINAPI
token_category_Release( ISpObjectTokenCategory
*iface
)
372 struct token_category
*This
= impl_from_ISpObjectTokenCategory( iface
);
373 ULONG ref
= InterlockedDecrement(&This
->ref
);
375 TRACE( "(%p) ref = %lu\n", This
, ref
);
379 if (This
->data_key
) ISpRegDataKey_Release( This
->data_key
);
386 static HRESULT WINAPI
token_category_SetData( ISpObjectTokenCategory
*iface
,
387 LPCWSTR name
, ULONG size
,
394 static HRESULT WINAPI
token_category_GetData( ISpObjectTokenCategory
*iface
,
395 LPCWSTR name
, ULONG
*size
,
402 static HRESULT WINAPI
token_category_SetStringValue( ISpObjectTokenCategory
*iface
,
403 LPCWSTR name
, LPCWSTR value
)
409 static HRESULT WINAPI
token_category_GetStringValue( ISpObjectTokenCategory
*iface
,
410 LPCWSTR name
, LPWSTR
*value
)
416 static HRESULT WINAPI
token_category_SetDWORD( ISpObjectTokenCategory
*iface
,
417 LPCWSTR name
, DWORD value
)
423 static HRESULT WINAPI
token_category_GetDWORD( ISpObjectTokenCategory
*iface
,
424 LPCWSTR name
, DWORD
*pdwValue
)
430 static HRESULT WINAPI
token_category_OpenKey( ISpObjectTokenCategory
*iface
,
431 LPCWSTR name
, ISpDataKey
**sub_key
)
437 static HRESULT WINAPI
token_category_CreateKey( ISpObjectTokenCategory
*iface
,
438 LPCWSTR name
, ISpDataKey
**sub_key
)
444 static HRESULT WINAPI
token_category_DeleteKey( ISpObjectTokenCategory
*iface
,
451 static HRESULT WINAPI
token_category_DeleteValue( ISpObjectTokenCategory
*iface
,
458 static HRESULT WINAPI
token_category_EnumKeys( ISpObjectTokenCategory
*iface
,
459 ULONG index
, LPWSTR
*sub_key
)
465 static HRESULT WINAPI
token_category_EnumValues( ISpObjectTokenCategory
*iface
,
466 ULONG index
, LPWSTR
*value
)
472 static HRESULT
parse_cat_id( const WCHAR
*str
, HKEY
*root
, const WCHAR
**sub_key
)
481 #define X(s) s, ARRAY_SIZE(s) - 1
482 { X(L
"HKEY_LOCAL_MACHINE\\"), HKEY_LOCAL_MACHINE
},
483 { X(L
"HKEY_CURRENT_USER\\"), HKEY_CURRENT_USER
},
488 int len
= lstrlenW( str
);
490 for (ptr
= table
; ptr
->name
; ptr
++)
492 if (len
>= ptr
->len
&& !wcsncmp( str
, ptr
->name
, ptr
->len
))
495 *sub_key
= str
+ ptr
->len
;
502 static HRESULT WINAPI
create_data_key_with_hkey( HKEY key
, ISpRegDataKey
**data_key
)
506 if (FAILED(hr
= CoCreateInstance( &CLSID_SpDataKey
, NULL
, CLSCTX_INPROC_SERVER
,
507 &IID_ISpRegDataKey
, (void **)data_key
) ))
510 if (FAILED(hr
= ISpRegDataKey_SetKey( *data_key
, key
, TRUE
)))
512 ISpRegDataKey_Release( *data_key
);
519 static HRESULT WINAPI
token_category_SetId( ISpObjectTokenCategory
*iface
,
520 LPCWSTR id
, BOOL create
)
522 struct token_category
*This
= impl_from_ISpObjectTokenCategory( iface
);
528 TRACE( "(%p)->(%s %d)\n", This
, debugstr_w( id
), create
);
530 if (This
->data_key
) return SPERR_ALREADY_INITIALIZED
;
532 hr
= parse_cat_id( id
, &root
, &subkey
);
533 if (hr
!= S_OK
) return SPERR_INVALID_REGISTRY_KEY
;
536 res
= RegCreateKeyExW( root
, subkey
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
538 res
= RegOpenKeyExW( root
, subkey
, 0, KEY_ALL_ACCESS
, &key
);
539 if (res
) return SPERR_INVALID_REGISTRY_KEY
;
541 if (FAILED(hr
= create_data_key_with_hkey( key
, &This
->data_key
)))
547 This
->id
= wcsdup( id
);
552 static HRESULT WINAPI
token_category_GetId( ISpObjectTokenCategory
*iface
,
559 static HRESULT WINAPI
token_category_GetDataKey( ISpObjectTokenCategory
*iface
,
560 SPDATAKEYLOCATION location
,
561 ISpDataKey
**data_key
)
567 struct token_with_score
569 ISpObjectToken
*token
;
575 ISpObjectTokenEnumBuilder ISpObjectTokenEnumBuilder_iface
;
580 struct token_with_score
*tokens
;
581 ULONG capacity
, count
;
585 static struct token_enum
*impl_from_ISpObjectTokenEnumBuilder( ISpObjectTokenEnumBuilder
*iface
)
587 return CONTAINING_RECORD( iface
, struct token_enum
, ISpObjectTokenEnumBuilder_iface
);
590 static HRESULT WINAPI
token_category_EnumTokens( ISpObjectTokenCategory
*iface
,
591 LPCWSTR req
, LPCWSTR opt
,
592 IEnumSpObjectTokens
**enum_tokens
)
594 struct token_category
*This
= impl_from_ISpObjectTokenCategory( iface
);
595 ISpObjectTokenEnumBuilder
*builder
;
596 struct data_key
*this_data_key
;
598 DWORD count
, max_subkey_size
, root_len
, token_id_size
;
600 WCHAR
*token_id
= NULL
;
601 ISpObjectToken
*token
= NULL
;
604 TRACE( "(%p)->(%s %s %p)\n", This
, debugstr_w( req
), debugstr_w( opt
), enum_tokens
);
606 if (!This
->data_key
) return SPERR_UNINITIALIZED
;
608 hr
= CoCreateInstance( &CLSID_SpObjectTokenEnum
, NULL
, CLSCTX_ALL
,
609 &IID_ISpObjectTokenEnumBuilder
, (void **)&builder
);
610 if (FAILED(hr
)) return hr
;
612 hr
= ISpObjectTokenEnumBuilder_SetAttribs( builder
, req
, opt
);
613 if (FAILED(hr
)) goto fail
;
615 this_data_key
= impl_from_ISpRegDataKey( This
->data_key
);
617 if (!RegOpenKeyExW( this_data_key
->key
, L
"Tokens", 0, KEY_ALL_ACCESS
, &tokens_key
))
619 RegQueryInfoKeyW( tokens_key
, NULL
, NULL
, NULL
, &count
, &max_subkey_size
, NULL
,
620 NULL
, NULL
, NULL
, NULL
, NULL
);
623 root_len
= wcslen( This
->id
);
624 token_id_size
= root_len
+ sizeof("\\Tokens\\") + max_subkey_size
;
625 token_id
= malloc( token_id_size
* sizeof(WCHAR
) );
631 root_len
= swprintf( token_id
, token_id_size
, L
"%ls%lsTokens\\",
632 This
->id
, This
->id
[root_len
- 1] == L
'\\' ? L
"" : L
"\\" );
634 for ( i
= 0; i
< count
; i
++ )
636 size
= max_subkey_size
;
637 hr
= HRESULT_FROM_WIN32(RegEnumKeyExW( tokens_key
, i
, token_id
+ root_len
, &size
, NULL
, NULL
, NULL
, NULL
));
638 if (FAILED(hr
)) goto fail
;
640 hr
= token_create( NULL
, &IID_ISpObjectToken
, (void **)&token
);
641 if (FAILED(hr
)) goto fail
;
643 hr
= ISpObjectToken_SetId( token
, NULL
, token_id
, FALSE
);
644 if (FAILED(hr
)) goto fail
;
646 hr
= ISpObjectTokenEnumBuilder_AddTokens( builder
, 1, &token
);
647 if (FAILED(hr
)) goto fail
;
648 ISpObjectToken_Release( token
);
652 hr
= ISpObjectTokenEnumBuilder_Sort( builder
, NULL
);
653 if (FAILED(hr
)) goto fail
;
656 hr
= ISpObjectTokenEnumBuilder_QueryInterface( builder
, &IID_IEnumSpObjectTokens
,
657 (void **)enum_tokens
);
660 ISpObjectTokenEnumBuilder_Release( builder
);
661 if ( token
) ISpObjectToken_Release( token
);
666 static HRESULT WINAPI
token_category_SetDefaultTokenId( ISpObjectTokenCategory
*iface
,
673 static HRESULT WINAPI
token_category_GetDefaultTokenId( ISpObjectTokenCategory
*iface
,
676 struct token_category
*This
= impl_from_ISpObjectTokenCategory( iface
);
677 struct data_key
*this_data_key
;
680 DWORD regvalue_size
= sizeof( regvalue
);
682 FIXME( "(%p)->(%p): semi-stub\n", iface
, id
);
685 return SPERR_UNINITIALIZED
;
690 /* todo: check HKCU's DefaultTokenId before */
692 this_data_key
= impl_from_ISpRegDataKey( This
->data_key
);
694 res
= RegGetValueW( this_data_key
->key
, NULL
, L
"DefaultDefaultTokenId", RRF_RT_REG_SZ
,
695 NULL
, ®value
, ®value_size
);
696 if (res
== ERROR_FILE_NOT_FOUND
) {
697 return SPERR_NOT_FOUND
;
698 } else if (res
!= ERROR_SUCCESS
) {
699 /* probably not the correct return value */
700 FIXME( "returning %08lx\n", res
);
704 *id
= CoTaskMemAlloc( regvalue_size
);
705 wcscpy( *id
, regvalue
);
710 const struct ISpObjectTokenCategoryVtbl token_category_vtbl
=
712 token_category_QueryInterface
,
713 token_category_AddRef
,
714 token_category_Release
,
715 token_category_SetData
,
716 token_category_GetData
,
717 token_category_SetStringValue
,
718 token_category_GetStringValue
,
719 token_category_SetDWORD
,
720 token_category_GetDWORD
,
721 token_category_OpenKey
,
722 token_category_CreateKey
,
723 token_category_DeleteKey
,
724 token_category_DeleteValue
,
725 token_category_EnumKeys
,
726 token_category_EnumValues
,
727 token_category_SetId
,
728 token_category_GetId
,
729 token_category_GetDataKey
,
730 token_category_EnumTokens
,
731 token_category_SetDefaultTokenId
,
732 token_category_GetDefaultTokenId
,
735 HRESULT
token_category_create( IUnknown
*outer
, REFIID iid
, void **obj
)
737 struct token_category
*This
= malloc( sizeof(*This
) );
740 if (!This
) return E_OUTOFMEMORY
;
741 This
->ISpObjectTokenCategory_iface
.lpVtbl
= &token_category_vtbl
;
743 This
->data_key
= NULL
;
746 hr
= ISpObjectTokenCategory_QueryInterface( &This
->ISpObjectTokenCategory_iface
, iid
, obj
);
748 ISpObjectTokenCategory_Release( &This
->ISpObjectTokenCategory_iface
);
752 static HRESULT WINAPI
token_enum_QueryInterface( ISpObjectTokenEnumBuilder
*iface
,
753 REFIID iid
, void **obj
)
755 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
757 TRACE( "(%p)->(%s %p)\n", This
, debugstr_guid( iid
), obj
);
759 if (IsEqualIID( iid
, &IID_IUnknown
) ||
760 IsEqualIID( iid
, &IID_IEnumSpObjectTokens
) ||
761 IsEqualIID( iid
, &IID_ISpObjectTokenEnumBuilder
))
763 ISpObjectTokenEnumBuilder_AddRef( iface
);
768 FIXME( "interface %s not implemented\n", debugstr_guid( iid
) );
770 return E_NOINTERFACE
;
773 static ULONG WINAPI
token_enum_AddRef( ISpObjectTokenEnumBuilder
*iface
)
775 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
776 ULONG ref
= InterlockedIncrement( &This
->ref
);
778 TRACE( "(%p) ref = %lu\n", This
, ref
);
782 static ULONG WINAPI
token_enum_Release( ISpObjectTokenEnumBuilder
*iface
)
784 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
785 ULONG ref
= InterlockedDecrement(&This
->ref
);
787 TRACE( "(%p) ref = %lu\n", This
, ref
);
796 for ( i
= 0; i
< This
->count
; i
++ )
797 if ( This
->tokens
[i
].token
)
798 ISpObjectToken_Release( This
->tokens
[i
].token
);
799 free( This
->tokens
);
807 static HRESULT WINAPI
token_enum_Next( ISpObjectTokenEnumBuilder
*iface
,
808 ULONG num
, ISpObjectToken
**tokens
,
811 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
814 TRACE( "(%p)->(%lu %p %p)\n", This
, num
, tokens
, fetched
);
816 if (!This
->init
) return SPERR_UNINITIALIZED
;
817 if (!fetched
&& num
!= 1) return E_POINTER
;
818 if (!tokens
) return E_POINTER
;
820 for ( i
= 0; i
< num
&& This
->index
< This
->count
; i
++, This
->index
++ )
822 ISpObjectToken_AddRef( This
->tokens
[This
->index
].token
);
823 tokens
[i
] = This
->tokens
[This
->index
].token
;
826 if (fetched
) *fetched
= i
;
828 return i
== num
? S_OK
: S_FALSE
;
831 static HRESULT WINAPI
token_enum_Skip( ISpObjectTokenEnumBuilder
*iface
,
838 static HRESULT WINAPI
token_enum_Reset( ISpObjectTokenEnumBuilder
*iface
)
844 static HRESULT WINAPI
token_enum_Clone( ISpObjectTokenEnumBuilder
*iface
,
845 IEnumSpObjectTokens
**clone
)
851 static HRESULT WINAPI
token_enum_Item( ISpObjectTokenEnumBuilder
*iface
,
852 ULONG index
, ISpObjectToken
**token
)
854 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
856 TRACE( "(%p)->(%lu %p)\n", This
, index
, token
);
858 if (!This
->init
) return SPERR_UNINITIALIZED
;
860 if (!token
) return E_POINTER
;
861 if (index
>= This
->count
) return SPERR_NO_MORE_ITEMS
;
863 ISpObjectToken_AddRef( This
->tokens
[index
].token
);
864 *token
= This
->tokens
[index
].token
;
869 static HRESULT WINAPI
token_enum_GetCount( ISpObjectTokenEnumBuilder
*iface
,
872 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
874 TRACE( "(%p)->(%p)\n", This
, count
);
876 if (!This
->init
) return SPERR_UNINITIALIZED
;
878 *count
= This
->count
;
882 static HRESULT WINAPI
token_enum_SetAttribs( ISpObjectTokenEnumBuilder
*iface
,
883 LPCWSTR req
, LPCWSTR opt
)
885 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
887 TRACE( "(%p)->(%s %s)\n", This
, debugstr_w( req
), debugstr_w( opt
) );
889 if (This
->init
) return SPERR_ALREADY_INITIALIZED
;
893 This
->req
= wcsdup( req
);
894 if (!This
->req
) goto out_of_mem
;
899 This
->opt
= wcsdup( opt
);
900 if (!This
->opt
) goto out_of_mem
;
908 return E_OUTOFMEMORY
;
911 static HRESULT
score_attributes( ISpObjectToken
*token
, const WCHAR
*attrs
,
912 BOOL match_all
, uint64_t *score
)
914 ISpDataKey
*attrs_key
;
915 WCHAR
*attr
, *attr_ctx
, *buf
;
927 if (FAILED(hr
= ISpObjectToken_OpenKey( token
, L
"Attributes", &attrs_key
)))
928 return hr
== SPERR_NOT_FOUND
? S_OK
: hr
;
930 memset( match
, 0, sizeof(match
) );
932 /* attrs is a semicolon-separated list of attribute clauses.
933 * Each clause consists of an attribute name and an optional operator and value.
934 * The meaning of a clause depends on the operator given:
935 * If no operator is given, the attribute must exist.
936 * If the operator is '=', the attribute must contain the given value.
937 * If the operator is '!=', the attribute must not exist or contain the given value.
939 if (!(buf
= wcsdup( attrs
))) return E_OUTOFMEMORY
;
940 for ( attr
= wcstok_s( buf
, L
";", &attr_ctx
), i
= 0; attr
&& i
< 64;
941 attr
= wcstok_s( NULL
, L
";", &attr_ctx
), i
++ )
943 WCHAR
*p
= wcspbrk( attr
, L
"!=" );
944 WCHAR op
= p
? *p
: L
'\0';
945 WCHAR
*value
= NULL
, *res
;
950 else if ( op
== L
'!' )
952 if ( *(p
+ 1) != L
'=' )
954 WARN( "invalid attr operator '!%lc'.\n", *(p
+ 1) );
963 hr
= ISpDataKey_GetStringValue( attrs_key
, attr
, &res
);
971 WCHAR
*val
, *val_ctx
;
974 for ( val
= wcstok_s( res
, L
";", &val_ctx
); val
&& !match
[i
];
975 val
= wcstok_s( NULL
, L
";", &val_ctx
) )
976 match
[i
] = !wcscmp( val
, value
);
978 if (op
== L
'!') match
[i
] = !match
[i
];
980 CoTaskMemFree( res
);
982 else if (hr
== SPERR_NOT_FOUND
)
985 if (op
== L
'!') match
[i
] = TRUE
;
990 if ( match_all
&& !match
[i
] )
998 /* Attributes in attrs are ordered from highest to lowest priority. */
999 for ( j
= 0; j
< i
; j
++ )
1001 *score
|= 1ULL << (i
- 1 - j
);
1009 static BOOL
grow_tokens_array( struct token_enum
*This
)
1011 struct token_with_score
*new_tokens
;
1014 if (This
->count
< This
->capacity
) return TRUE
;
1016 if (This
->capacity
> 0)
1018 new_cap
= This
->capacity
* 2;
1019 new_tokens
= realloc( This
->tokens
, new_cap
* sizeof(*new_tokens
) );
1024 new_tokens
= malloc( sizeof(*new_tokens
) );
1027 if (!new_tokens
) return FALSE
;
1029 This
->tokens
= new_tokens
;
1030 This
->capacity
= new_cap
;
1034 static HRESULT WINAPI
token_enum_AddTokens( ISpObjectTokenEnumBuilder
*iface
,
1035 ULONG num
, ISpObjectToken
**tokens
)
1037 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
1042 TRACE( "(%p)->(%lu %p)\n", iface
, num
, tokens
);
1044 if (!This
->init
) return SPERR_UNINITIALIZED
;
1045 if (!tokens
) return E_POINTER
;
1047 for ( i
= 0; i
< num
; i
++ )
1049 if (!tokens
[i
]) return E_POINTER
;
1051 hr
= score_attributes( tokens
[i
], This
->req
, TRUE
, &score
);
1052 if (FAILED(hr
)) return hr
;
1053 if (!score
) continue;
1055 hr
= score_attributes( tokens
[i
], This
->opt
, FALSE
, &score
);
1056 if (FAILED(hr
)) return hr
;
1058 if (!grow_tokens_array( This
)) return E_OUTOFMEMORY
;
1059 ISpObjectToken_AddRef( tokens
[i
] );
1060 This
->tokens
[This
->count
].token
= tokens
[i
];
1061 This
->tokens
[This
->count
].score
= score
;
1068 static HRESULT WINAPI
token_enum_AddTokensFromDataKey( ISpObjectTokenEnumBuilder
*iface
,
1069 ISpDataKey
*data_key
,
1070 LPCWSTR sub_key
, LPCWSTR cat_id
)
1076 static HRESULT WINAPI
token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuilder
*iface
,
1077 IEnumSpObjectTokens
*token_enum
)
1083 static int __cdecl
token_with_score_cmp( const void *a
, const void *b
)
1085 const struct token_with_score
*ta
= a
, *tb
= b
;
1087 if (ta
->score
> tb
->score
) return -1;
1088 else if (ta
->score
< tb
->score
) return 1;
1092 static HRESULT WINAPI
token_enum_Sort( ISpObjectTokenEnumBuilder
*iface
,
1095 struct token_enum
*This
= impl_from_ISpObjectTokenEnumBuilder( iface
);
1097 TRACE( "(%p)->(%s).\n", iface
, debugstr_w(first
) );
1099 if (!This
->init
) return SPERR_UNINITIALIZED
;
1100 if (!This
->tokens
) return S_OK
;
1104 FIXME( "first != NULL is not implemented.\n" );
1109 qsort( This
->tokens
, This
->count
, sizeof(*This
->tokens
), token_with_score_cmp
);
1114 const struct ISpObjectTokenEnumBuilderVtbl token_enum_vtbl
=
1116 token_enum_QueryInterface
,
1124 token_enum_GetCount
,
1125 token_enum_SetAttribs
,
1126 token_enum_AddTokens
,
1127 token_enum_AddTokensFromDataKey
,
1128 token_enum_AddTokensFromTokenEnum
,
1132 HRESULT
token_enum_create( IUnknown
*outer
, REFIID iid
, void **obj
)
1134 struct token_enum
*This
= malloc( sizeof(*This
) );
1137 if (!This
) return E_OUTOFMEMORY
;
1138 This
->ISpObjectTokenEnumBuilder_iface
.lpVtbl
= &token_enum_vtbl
;
1143 This
->tokens
= NULL
;
1144 This
->capacity
= This
->count
= 0;
1147 hr
= ISpObjectTokenEnumBuilder_QueryInterface( &This
->ISpObjectTokenEnumBuilder_iface
, iid
, obj
);
1149 ISpObjectTokenEnumBuilder_Release( &This
->ISpObjectTokenEnumBuilder_iface
);
1153 static HRESULT WINAPI
token_QueryInterface( ISpObjectToken
*iface
,
1154 REFIID iid
, void **obj
)
1156 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1158 TRACE( "(%p)->(%s %p)\n", This
, debugstr_guid( iid
), obj
);
1160 if (IsEqualIID( iid
, &IID_IUnknown
) ||
1161 IsEqualIID( iid
, &IID_ISpDataKey
) ||
1162 IsEqualIID( iid
, &IID_ISpObjectToken
))
1164 ISpObjectToken_AddRef( iface
);
1169 FIXME( "interface %s not implemented\n", debugstr_guid( iid
) );
1171 return E_NOINTERFACE
;
1174 static ULONG WINAPI
token_AddRef( ISpObjectToken
*iface
)
1176 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1177 ULONG ref
= InterlockedIncrement( &This
->ref
);
1179 TRACE( "(%p) ref = %lu\n", This
, ref
);
1183 static ULONG WINAPI
token_Release( ISpObjectToken
*iface
)
1185 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1186 ULONG ref
= InterlockedDecrement(&This
->ref
);
1188 TRACE( "(%p) ref = %lu\n", This
, ref
);
1192 if (This
->data_key
) ISpRegDataKey_Release( This
->data_key
);
1193 free( This
->token_id
);
1200 static HRESULT WINAPI
token_SetData( ISpObjectToken
*iface
,
1201 LPCWSTR name
, ULONG size
,
1208 static HRESULT WINAPI
token_GetData( ISpObjectToken
*iface
,
1209 LPCWSTR name
, ULONG
*size
,
1216 static HRESULT WINAPI
token_SetStringValue( ISpObjectToken
*iface
,
1217 LPCWSTR name
, LPCWSTR value
)
1219 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1221 TRACE( "%p, %s, %s\n", This
, debugstr_w(name
), debugstr_w(value
) );
1223 return ISpRegDataKey_SetStringValue( This
->data_key
, name
, value
);
1226 static HRESULT WINAPI
token_GetStringValue( ISpObjectToken
*iface
,
1227 LPCWSTR name
, LPWSTR
*value
)
1229 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1231 TRACE( "%p, %s, %p\n", This
, debugstr_w(name
), value
);
1233 return ISpRegDataKey_GetStringValue( This
->data_key
, name
, value
);
1236 static HRESULT WINAPI
token_SetDWORD( ISpObjectToken
*iface
,
1237 LPCWSTR name
, DWORD value
)
1243 static HRESULT WINAPI
token_GetDWORD( ISpObjectToken
*iface
,
1244 LPCWSTR name
, DWORD
*pdwValue
)
1250 static HRESULT WINAPI
token_OpenKey( ISpObjectToken
*iface
,
1251 LPCWSTR name
, ISpDataKey
**sub_key
)
1253 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1255 TRACE( "%p, %s, %p\n", This
, debugstr_w(name
), sub_key
);
1257 return ISpRegDataKey_OpenKey( This
->data_key
, name
, sub_key
);
1260 static HRESULT WINAPI
token_CreateKey( ISpObjectToken
*iface
,
1261 LPCWSTR name
, ISpDataKey
**sub_key
)
1263 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1265 TRACE( "%p, %s, %p\n", iface
, debugstr_w(name
), sub_key
);
1267 return ISpRegDataKey_CreateKey( This
->data_key
, name
, sub_key
);
1270 static HRESULT WINAPI
token_DeleteKey( ISpObjectToken
*iface
,
1277 static HRESULT WINAPI
token_DeleteValue( ISpObjectToken
*iface
,
1284 static HRESULT WINAPI
token_EnumKeys( ISpObjectToken
*iface
,
1285 ULONG index
, LPWSTR
*sub_key
)
1291 static HRESULT WINAPI
token_EnumValues( ISpObjectToken
*iface
,
1292 ULONG index
, LPWSTR
*value
)
1298 static HRESULT WINAPI
token_SetId( ISpObjectToken
*iface
,
1299 LPCWSTR category_id
, LPCWSTR token_id
,
1302 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1306 const WCHAR
*subkey
;
1308 FIXME( "(%p)->(%s %s %d): semi-stub\n", This
, debugstr_w( category_id
),
1309 debugstr_w(token_id
), create
);
1311 if (This
->data_key
) return SPERR_ALREADY_INITIALIZED
;
1313 if (!token_id
) return E_POINTER
;
1315 hr
= parse_cat_id( token_id
, &root
, &subkey
);
1316 if (hr
!= S_OK
) return SPERR_NOT_FOUND
;
1319 res
= RegCreateKeyExW( root
, subkey
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &key
, NULL
);
1321 res
= RegOpenKeyExW( root
, subkey
, 0, KEY_ALL_ACCESS
, &key
);
1322 if (res
) return SPERR_NOT_FOUND
;
1324 hr
= create_data_key_with_hkey( key
, &This
->data_key
);
1331 This
->token_id
= wcsdup(token_id
);
1336 static HRESULT WINAPI
token_GetId( ISpObjectToken
*iface
,
1339 struct object_token
*This
= impl_from_ISpObjectToken( iface
);
1341 TRACE( "%p, %p\n", This
, token_id
);
1343 if (!This
->data_key
)
1344 return SPERR_UNINITIALIZED
;
1349 if (!This
->token_id
)
1351 FIXME("Loading default category not supported.\n");
1355 *token_id
= CoTaskMemAlloc( (wcslen(This
->token_id
) + 1) * sizeof(WCHAR
));
1357 return E_OUTOFMEMORY
;
1359 wcscpy(*token_id
, This
->token_id
);
1363 static HRESULT WINAPI
token_GetCategory( ISpObjectToken
*iface
,
1364 ISpObjectTokenCategory
**category
)
1370 static HRESULT WINAPI
token_CreateInstance( ISpObjectToken
*iface
,
1372 DWORD class_context
,
1379 ISpObjectWithToken
*obj_token_iface
;
1382 TRACE( "%p, %p, %#lx, %s, %p\n", iface
, outer
, class_context
, debugstr_guid( riid
), object
);
1384 if (FAILED(hr
= ISpObjectToken_GetStringValue( iface
, L
"CLSID", &clsid_str
)))
1387 hr
= CLSIDFromString( clsid_str
, &clsid
);
1388 CoTaskMemFree( clsid_str
);
1392 if (FAILED(hr
= CoCreateInstance( &clsid
, outer
, class_context
, &IID_IUnknown
, (void **)&unk
)))
1395 /* Call ISpObjectWithToken::SetObjectToken if the interface is available. */
1396 if (SUCCEEDED(IUnknown_QueryInterface( unk
, &IID_ISpObjectWithToken
, (void **)&obj_token_iface
)))
1398 hr
= ISpObjectWithToken_SetObjectToken( obj_token_iface
, iface
);
1399 ISpObjectWithToken_Release( obj_token_iface
);
1404 hr
= IUnknown_QueryInterface( unk
, riid
, object
);
1407 IUnknown_Release( unk
);
1411 static HRESULT WINAPI
token_GetStorageFileName( ISpObjectToken
*iface
,
1422 static HRESULT WINAPI
token_RemoveStorageFileName( ISpObjectToken
*iface
,
1431 static HRESULT WINAPI
token_Remove( ISpObjectToken
*iface
,
1438 static HRESULT WINAPI
token_IsUISupported( ISpObjectToken
*iface
,
1441 ULONG extra_data_size
,
1449 static HRESULT WINAPI
token_DisplayUI( ISpObjectToken
*iface
,
1454 ULONG extra_data_size
,
1461 static HRESULT WINAPI
token_MatchesAttributes( ISpObjectToken
*iface
,
1469 const struct ISpObjectTokenVtbl token_vtbl
=
1471 token_QueryInterface
,
1476 token_SetStringValue
,
1477 token_GetStringValue
,
1489 token_CreateInstance
,
1490 token_GetStorageFileName
,
1491 token_RemoveStorageFileName
,
1493 token_IsUISupported
,
1495 token_MatchesAttributes
1498 HRESULT
token_create( IUnknown
*outer
, REFIID iid
, void **obj
)
1500 struct object_token
*This
= malloc( sizeof(*This
) );
1503 if (!This
) return E_OUTOFMEMORY
;
1504 This
->ISpObjectToken_iface
.lpVtbl
= &token_vtbl
;
1507 This
->data_key
= NULL
;
1508 This
->token_id
= NULL
;
1510 hr
= ISpObjectToken_QueryInterface( &This
->ISpObjectToken_iface
, iid
, obj
);
1512 ISpObjectToken_Release( &This
->ISpObjectToken_iface
);