diff --git a/dlls/sapi/main.c b/dlls/sapi/main.c
index edbb5d9bd5a69e34df8c38cce48b986b112b7ef8..ea164a5c98406ec7af16b6e30f323ed7c85a70e5 100644
--- a/dlls/sapi/main.c
+++ b/dlls/sapi/main.c
@@ -107,6 +107,7 @@ static const struct IClassFactoryVtbl class_factory_vtbl =
 };
 
 static struct class_factory data_key_cf       = { { &class_factory_vtbl }, data_key_create };
+static struct class_factory token_enum_cf     = { { &class_factory_vtbl }, token_enum_create };
 
 /******************************************************************
  *             DllGetClassObject
@@ -119,6 +120,8 @@ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **obj )
 
     if (IsEqualCLSID( clsid, &CLSID_SpDataKey ))
         cf = &data_key_cf.IClassFactory_iface;
+    else if (IsEqualCLSID( clsid, &CLSID_SpObjectTokenEnum ))
+        cf = &token_enum_cf.IClassFactory_iface;
 
     if (!cf) return CLASS_E_CLASSNOTAVAILABLE;
 
diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h
index 7809f5025d3b86b59a92c43897e657318003da4b..7a5c14e9db6f1e6eebcafdd7675718fbbeaac4f6 100644
--- a/dlls/sapi/sapi_private.h
+++ b/dlls/sapi/sapi_private.h
@@ -19,6 +19,7 @@
  */
 
 HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
+HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN;
 
 static inline void * __WINE_ALLOC_SIZE(1) heap_alloc(size_t len)
 {
diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c
index a274f5ff69d04790b8f4619d12ccb9cf6a960a76..03ce0a74f02ff0c1274be90fa9957d6225a3e5d2 100644
--- a/dlls/sapi/token.c
+++ b/dlls/sapi/token.c
@@ -226,3 +226,168 @@ HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj )
     ISpRegDataKey_Release( &This->ISpRegDataKey_iface );
     return hr;
 }
+
+struct token_enum
+{
+    ISpObjectTokenEnumBuilder ISpObjectTokenEnumBuilder_iface;
+    LONG ref;
+};
+
+struct token_enum *impl_from_ISpObjectTokenEnumBuilder( ISpObjectTokenEnumBuilder *iface )
+{
+    return CONTAINING_RECORD( iface, struct token_enum, ISpObjectTokenEnumBuilder_iface );
+}
+
+static HRESULT WINAPI token_enum_QueryInterface( ISpObjectTokenEnumBuilder *iface,
+                                                 REFIID iid, void **obj )
+{
+    struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
+
+    TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
+
+    if (IsEqualIID( iid, &IID_IUnknown ) ||
+        IsEqualIID( iid, &IID_IEnumSpObjectTokens ) ||
+        IsEqualIID( iid, &IID_ISpObjectTokenEnumBuilder ))
+    {
+        ISpObjectTokenEnumBuilder_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_enum_AddRef( ISpObjectTokenEnumBuilder *iface )
+{
+    struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
+    ULONG ref = InterlockedIncrement( &This->ref );
+
+    TRACE( "(%p) ref = %u\n", This, ref );
+    return ref;
+}
+
+static ULONG WINAPI token_enum_Release( ISpObjectTokenEnumBuilder *iface )
+{
+    struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface );
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE( "(%p) ref = %u\n", This, ref );
+
+    if (!ref)
+        heap_free( This );
+
+    return ref;
+}
+
+static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface,
+                                       ULONG num, ISpObjectToken **tokens,
+                                       ULONG *fetched )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_Skip( ISpObjectTokenEnumBuilder *iface,
+                                       ULONG num )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_Reset( ISpObjectTokenEnumBuilder *iface)
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_Clone( ISpObjectTokenEnumBuilder *iface,
+                                        IEnumSpObjectTokens **clone )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface,
+                                       ULONG index, ISpObjectToken **token )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_GetCount( ISpObjectTokenEnumBuilder *iface,
+                                           ULONG *count )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_SetAttribs( ISpObjectTokenEnumBuilder *iface,
+                                             LPCWSTR req, LPCWSTR opt)
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface,
+                                            ULONG num, ISpObjectToken **tokens )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_AddTokensFromDataKey( ISpObjectTokenEnumBuilder *iface,
+                                                       ISpDataKey *data_key,
+                                                       LPCWSTR sub_key, LPCWSTR cat_id )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuilder *iface,
+                                                         IEnumSpObjectTokens *token_enum )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface,
+                                       LPCWSTR first )
+{
+    FIXME( "stub\n" );
+    return E_NOTIMPL;
+}
+
+const struct ISpObjectTokenEnumBuilderVtbl token_enum_vtbl =
+{
+    token_enum_QueryInterface,
+    token_enum_AddRef,
+    token_enum_Release,
+    token_enum_Next,
+    token_enum_Skip,
+    token_enum_Reset,
+    token_enum_Clone,
+    token_enum_Item,
+    token_enum_GetCount,
+    token_enum_SetAttribs,
+    token_enum_AddTokens,
+    token_enum_AddTokensFromDataKey,
+    token_enum_AddTokensFromTokenEnum,
+    token_enum_Sort
+};
+
+HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj )
+{
+    struct token_enum *This = heap_alloc( sizeof(*This) );
+    HRESULT hr;
+
+    if (!This) return E_OUTOFMEMORY;
+    This->ISpObjectTokenEnumBuilder_iface.lpVtbl = &token_enum_vtbl;
+    This->ref = 1;
+
+    hr = ISpObjectTokenEnumBuilder_QueryInterface( &This->ISpObjectTokenEnumBuilder_iface, iid, obj );
+
+    ISpObjectTokenEnumBuilder_Release( &This->ISpObjectTokenEnumBuilder_iface );
+    return hr;
+}