1 /* WinRT Windows.Security.Credentials.UI Implementation
3 * Copyright 2022 Bernhard Kölbl for CodeWeavers
4 * Copyright 2022 Rémi Bernon for CodeWeavers
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
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(credentials
);
27 #define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0)
31 IWineAsyncInfoImpl IWineAsyncInfoImpl_iface
;
32 IAsyncInfo IAsyncInfo_iface
;
33 IInspectable
*IInspectable_outer
;
36 async_operation_callback callback
;
37 TP_WORK
*async_run_work
;
42 IWineAsyncOperationCompletedHandler
*handler
;
48 static inline struct async_info
*impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl
*iface
)
50 return CONTAINING_RECORD( iface
, struct async_info
, IWineAsyncInfoImpl_iface
);
53 static HRESULT WINAPI
async_impl_QueryInterface( IWineAsyncInfoImpl
*iface
, REFIID iid
, void **out
)
55 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
57 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
59 if (IsEqualGUID( iid
, &IID_IUnknown
) ||
60 IsEqualGUID( iid
, &IID_IInspectable
) ||
61 IsEqualGUID( iid
, &IID_IAgileObject
) ||
62 IsEqualGUID( iid
, &IID_IWineAsyncInfoImpl
))
64 IInspectable_AddRef( (*out
= &impl
->IWineAsyncInfoImpl_iface
) );
68 if (IsEqualGUID( iid
, &IID_IAsyncInfo
))
70 IInspectable_AddRef( (*out
= &impl
->IAsyncInfo_iface
) );
74 FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid
) );
79 static ULONG WINAPI
async_impl_AddRef( IWineAsyncInfoImpl
*iface
)
81 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
82 ULONG ref
= InterlockedIncrement( &impl
->ref
);
83 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
87 static ULONG WINAPI
async_impl_Release( IWineAsyncInfoImpl
*iface
)
89 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
90 ULONG ref
= InterlockedDecrement( &impl
->ref
);
91 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
95 if (impl
->handler
&& impl
->handler
!= HANDLER_NOT_SET
) IWineAsyncOperationCompletedHandler_Release( impl
->handler
);
96 IAsyncInfo_Close( &impl
->IAsyncInfo_iface
);
97 if (impl
->param
) IUnknown_Release( impl
->param
);
98 if (impl
->invoker
) IUnknown_Release( impl
->invoker
);
99 impl
->cs
.DebugInfo
->Spare
[0] = 0;
100 DeleteCriticalSection( &impl
->cs
);
107 static HRESULT WINAPI
async_impl_put_Completed( IWineAsyncInfoImpl
*iface
, IWineAsyncOperationCompletedHandler
*handler
)
109 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
112 TRACE( "iface %p, handler %p.\n", iface
, handler
);
114 EnterCriticalSection( &impl
->cs
);
115 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
116 else if (impl
->handler
!= HANDLER_NOT_SET
) hr
= E_ILLEGAL_DELEGATE_ASSIGNMENT
;
117 else if ((impl
->handler
= handler
))
119 IWineAsyncOperationCompletedHandler_AddRef( impl
->handler
);
121 if (impl
->status
> Started
)
123 IInspectable
*operation
= impl
->IInspectable_outer
;
124 AsyncStatus status
= impl
->status
;
125 impl
->handler
= NULL
; /* Prevent concurrent invoke. */
126 LeaveCriticalSection( &impl
->cs
);
128 IWineAsyncOperationCompletedHandler_Invoke( handler
, operation
, status
);
129 IWineAsyncOperationCompletedHandler_Release( handler
);
134 LeaveCriticalSection( &impl
->cs
);
139 static HRESULT WINAPI
async_impl_get_Completed( IWineAsyncInfoImpl
*iface
, IWineAsyncOperationCompletedHandler
**handler
)
141 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
144 TRACE( "iface %p, handler %p.\n", iface
, handler
);
146 EnterCriticalSection( &impl
->cs
);
147 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
148 if (impl
->handler
== NULL
|| impl
->handler
== HANDLER_NOT_SET
) *handler
= NULL
;
149 else IWineAsyncOperationCompletedHandler_AddRef( (*handler
= impl
->handler
) );
150 LeaveCriticalSection( &impl
->cs
);
155 static HRESULT WINAPI
async_impl_get_Result( IWineAsyncInfoImpl
*iface
, PROPVARIANT
*result
)
157 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
158 HRESULT hr
= E_ILLEGAL_METHOD_CALL
;
160 TRACE( "iface %p, result %p.\n", iface
, result
);
162 EnterCriticalSection( &impl
->cs
);
163 if (impl
->status
== Completed
|| impl
->status
== Error
)
165 PropVariantCopy( result
, &impl
->result
);
168 LeaveCriticalSection( &impl
->cs
);
173 static HRESULT WINAPI
async_impl_Start( IWineAsyncInfoImpl
*iface
)
175 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
177 TRACE( "iface %p.\n", iface
);
179 /* keep the async alive in the callback */
180 IInspectable_AddRef( impl
->IInspectable_outer
);
181 SubmitThreadpoolWork( impl
->async_run_work
);
186 static const struct IWineAsyncInfoImplVtbl async_impl_vtbl
=
188 /* IUnknown methods */
189 async_impl_QueryInterface
,
192 /* IWineAsyncInfoImpl */
193 async_impl_put_Completed
,
194 async_impl_get_Completed
,
195 async_impl_get_Result
,
199 DEFINE_IINSPECTABLE_OUTER( async_info
, IAsyncInfo
, struct async_info
, IInspectable_outer
)
201 static HRESULT WINAPI
async_info_get_Id( IAsyncInfo
*iface
, UINT32
*id
)
203 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
206 TRACE( "iface %p, id %p.\n", iface
, id
);
208 EnterCriticalSection( &impl
->cs
);
209 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
211 LeaveCriticalSection( &impl
->cs
);
216 static HRESULT WINAPI
async_info_get_Status( IAsyncInfo
*iface
, AsyncStatus
*status
)
218 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
221 TRACE( "iface %p, status %p.\n", iface
, status
);
223 EnterCriticalSection( &impl
->cs
);
224 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
225 *status
= impl
->status
;
226 LeaveCriticalSection( &impl
->cs
);
231 static HRESULT WINAPI
async_info_get_ErrorCode( IAsyncInfo
*iface
, HRESULT
*error_code
)
233 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
236 TRACE( "iface %p, error_code %p.\n", iface
, error_code
);
238 EnterCriticalSection( &impl
->cs
);
239 if (impl
->status
== Closed
) *error_code
= hr
= E_ILLEGAL_METHOD_CALL
;
240 else *error_code
= impl
->hr
;
241 LeaveCriticalSection( &impl
->cs
);
246 static HRESULT WINAPI
async_info_Cancel( IAsyncInfo
*iface
)
248 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
251 TRACE( "iface %p.\n", iface
);
253 EnterCriticalSection( &impl
->cs
);
254 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
255 else if (impl
->status
== Started
) impl
->status
= Canceled
;
256 LeaveCriticalSection( &impl
->cs
);
261 static HRESULT WINAPI
async_info_Close( IAsyncInfo
*iface
)
263 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
266 TRACE( "iface %p.\n", iface
);
268 EnterCriticalSection( &impl
->cs
);
269 if (impl
->status
== Started
)
270 hr
= E_ILLEGAL_STATE_CHANGE
;
271 else if (impl
->status
!= Closed
)
273 CloseThreadpoolWork( impl
->async_run_work
);
274 impl
->async_run_work
= NULL
;
275 impl
->status
= Closed
;
277 LeaveCriticalSection( &impl
->cs
);
282 static const struct IAsyncInfoVtbl async_info_vtbl
=
284 /* IUnknown methods */
285 async_info_QueryInterface
,
288 /* IInspectable methods */
290 async_info_GetRuntimeClassName
,
291 async_info_GetTrustLevel
,
294 async_info_get_Status
,
295 async_info_get_ErrorCode
,
300 static void CALLBACK
async_info_callback( TP_CALLBACK_INSTANCE
*instance
, void *iface
, TP_WORK
*work
)
302 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
303 IInspectable
*operation
= impl
->IInspectable_outer
;
307 hr
= impl
->callback( impl
->invoker
, impl
->param
, &result
);
309 EnterCriticalSection( &impl
->cs
);
310 if (impl
->status
!= Closed
) impl
->status
= FAILED(hr
) ? Error
: Completed
;
311 PropVariantCopy( &impl
->result
, &result
);
314 if (impl
->handler
!= NULL
&& impl
->handler
!= HANDLER_NOT_SET
)
316 IWineAsyncOperationCompletedHandler
*handler
= impl
->handler
;
317 AsyncStatus status
= impl
->status
;
318 impl
->handler
= NULL
; /* Prevent concurrent invoke. */
319 LeaveCriticalSection( &impl
->cs
);
321 IWineAsyncOperationCompletedHandler_Invoke( handler
, operation
, status
);
322 IWineAsyncOperationCompletedHandler_Release( handler
);
324 else LeaveCriticalSection( &impl
->cs
);
326 /* release refcount acquired in Start */
327 IInspectable_Release( operation
);
329 PropVariantClear( &result
);
332 static HRESULT
async_info_create( IUnknown
*invoker
, IUnknown
*param
, async_operation_callback callback
,
333 IInspectable
*outer
, IWineAsyncInfoImpl
**out
)
335 struct async_info
*impl
;
338 if (!(impl
= calloc( 1, sizeof(struct async_info
) ))) return E_OUTOFMEMORY
;
339 impl
->IWineAsyncInfoImpl_iface
.lpVtbl
= &async_impl_vtbl
;
340 impl
->IAsyncInfo_iface
.lpVtbl
= &async_info_vtbl
;
341 impl
->IInspectable_outer
= outer
;
344 impl
->callback
= callback
;
345 impl
->handler
= HANDLER_NOT_SET
;
346 impl
->status
= Started
;
347 if (!(impl
->async_run_work
= CreateThreadpoolWork( async_info_callback
, &impl
->IWineAsyncInfoImpl_iface
, NULL
)))
349 hr
= HRESULT_FROM_WIN32( GetLastError() );
354 if ((impl
->invoker
= invoker
)) IUnknown_AddRef( impl
->invoker
);
355 if ((impl
->param
= param
)) IUnknown_AddRef( impl
->param
);
357 InitializeCriticalSectionEx( &impl
->cs
, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
);
358 impl
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)( __FILE__
": async_info.cs" );
360 *out
= &impl
->IWineAsyncInfoImpl_iface
;
364 struct async_user_consent_verifier_availability
366 IAsyncOperation_UserConsentVerifierAvailability IAsyncOperation_UserConsentVerifierAvailability_iface
;
367 IWineAsyncInfoImpl
*IWineAsyncInfoImpl_inner
;
371 static inline struct async_user_consent_verifier_availability
*impl_from_IAsyncOperation_UserConsentVerifierAvailability( IAsyncOperation_UserConsentVerifierAvailability
*iface
)
373 return CONTAINING_RECORD( iface
, struct async_user_consent_verifier_availability
, IAsyncOperation_UserConsentVerifierAvailability_iface
);
376 static HRESULT WINAPI
async_user_consent_verifier_availability_QueryInterface( IAsyncOperation_UserConsentVerifierAvailability
*iface
, REFIID iid
, void **out
)
378 struct async_user_consent_verifier_availability
*impl
= impl_from_IAsyncOperation_UserConsentVerifierAvailability( iface
);
380 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
382 if (IsEqualGUID( iid
, &IID_IUnknown
) ||
383 IsEqualGUID( iid
, &IID_IInspectable
) ||
384 IsEqualGUID( iid
, &IID_IAgileObject
) ||
385 IsEqualGUID( iid
, &IID_IAsyncOperation_UserConsentVerifierAvailability
))
387 IInspectable_AddRef( (*out
= &impl
->IAsyncOperation_UserConsentVerifierAvailability_iface
) );
391 return IWineAsyncInfoImpl_QueryInterface( impl
->IWineAsyncInfoImpl_inner
, iid
, out
);
394 static ULONG WINAPI
async_user_consent_verifier_availability_AddRef( IAsyncOperation_UserConsentVerifierAvailability
*iface
)
396 struct async_user_consent_verifier_availability
*impl
= impl_from_IAsyncOperation_UserConsentVerifierAvailability( iface
);
397 ULONG ref
= InterlockedIncrement( &impl
->ref
);
398 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
402 static ULONG WINAPI
async_user_consent_verifier_availability_Release( IAsyncOperation_UserConsentVerifierAvailability
*iface
)
404 struct async_user_consent_verifier_availability
*impl
= impl_from_IAsyncOperation_UserConsentVerifierAvailability( iface
);
405 ULONG ref
= InterlockedDecrement( &impl
->ref
);
406 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
410 /* guard against re-entry if inner releases an outer iface */
411 InterlockedIncrement( &impl
->ref
);
412 IWineAsyncInfoImpl_Release( impl
->IWineAsyncInfoImpl_inner
);
419 static HRESULT WINAPI
async_user_consent_verifier_availability_GetIids( IAsyncOperation_UserConsentVerifierAvailability
*iface
, ULONG
*iid_count
, IID
**iids
)
421 FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
425 static HRESULT WINAPI
async_user_consent_verifier_availability_GetRuntimeClassName( IAsyncOperation_UserConsentVerifierAvailability
*iface
, HSTRING
*class_name
)
427 return WindowsCreateString( L
"Windows.Foundation.IAsyncOperation`1<Windows.Security.Credentials.UI.UserConsentVerifierAvailability>",
428 ARRAY_SIZE(L
"Windows.Foundation.IAsyncOperation`1<Windows.Security.Credentials.UI.UserConsentVerifierAvailability>"),
432 static HRESULT WINAPI
async_user_consent_verifier_availability_GetTrustLevel( IAsyncOperation_UserConsentVerifierAvailability
*iface
, TrustLevel
*trust_level
)
434 FIXME( "iface %p, trust_level %p stub!\n", iface
, trust_level
);
438 static HRESULT WINAPI
async_user_consent_verifier_availability_put_Completed( IAsyncOperation_UserConsentVerifierAvailability
*iface
,
439 IAsyncOperationCompletedHandler_UserConsentVerifierAvailability
*UserConsentVerifierAvailability_handler
)
441 IWineAsyncOperationCompletedHandler
*handler
= (IWineAsyncOperationCompletedHandler
*)UserConsentVerifierAvailability_handler
;
442 struct async_user_consent_verifier_availability
*impl
= impl_from_IAsyncOperation_UserConsentVerifierAvailability( iface
);
443 TRACE( "iface %p, handler %p.\n", iface
, handler
);
444 return IWineAsyncInfoImpl_put_Completed( impl
->IWineAsyncInfoImpl_inner
, (IWineAsyncOperationCompletedHandler
*)handler
);
447 static HRESULT WINAPI
async_user_consent_verifier_availability_get_Completed( IAsyncOperation_UserConsentVerifierAvailability
*iface
,
448 IAsyncOperationCompletedHandler_UserConsentVerifierAvailability
**UserConsentVerifierAvailability_handler
)
450 IWineAsyncOperationCompletedHandler
**handler
= (IWineAsyncOperationCompletedHandler
**)UserConsentVerifierAvailability_handler
;
451 struct async_user_consent_verifier_availability
*impl
= impl_from_IAsyncOperation_UserConsentVerifierAvailability( iface
);
452 TRACE( "iface %p, handler %p.\n", iface
, handler
);
453 return IWineAsyncInfoImpl_get_Completed( impl
->IWineAsyncInfoImpl_inner
, (IWineAsyncOperationCompletedHandler
**)handler
);
456 static HRESULT WINAPI
async_user_consent_verifier_availability_GetResults( IAsyncOperation_UserConsentVerifierAvailability
*iface
, UserConsentVerifierAvailability
*results
)
458 struct async_user_consent_verifier_availability
*impl
= impl_from_IAsyncOperation_UserConsentVerifierAvailability( iface
);
459 PROPVARIANT result
= {.vt
= VT_UI4
};
462 TRACE( "iface %p, results %p.\n", iface
, results
);
464 hr
= IWineAsyncInfoImpl_get_Result( impl
->IWineAsyncInfoImpl_inner
, &result
);
466 *results
= result
.ulVal
;
467 PropVariantClear( &result
);
471 static const struct IAsyncOperation_UserConsentVerifierAvailabilityVtbl async_user_consent_verifier_availability_vtbl
=
473 /* IUnknown methods */
474 async_user_consent_verifier_availability_QueryInterface
,
475 async_user_consent_verifier_availability_AddRef
,
476 async_user_consent_verifier_availability_Release
,
477 /* IInspectable methods */
478 async_user_consent_verifier_availability_GetIids
,
479 async_user_consent_verifier_availability_GetRuntimeClassName
,
480 async_user_consent_verifier_availability_GetTrustLevel
,
481 /* IAsyncOperation<UserConsentVerifierAvailability> */
482 async_user_consent_verifier_availability_put_Completed
,
483 async_user_consent_verifier_availability_get_Completed
,
484 async_user_consent_verifier_availability_GetResults
,
487 HRESULT
async_operation_user_consent_verifier_availability_create( IUnknown
*invoker
, IUnknown
*param
, async_operation_callback callback
,
488 IAsyncOperation_UserConsentVerifierAvailability
**out
)
490 struct async_user_consent_verifier_availability
*impl
;
494 if (!(impl
= calloc( 1, sizeof(*impl
) ))) return E_OUTOFMEMORY
;
495 impl
->IAsyncOperation_UserConsentVerifierAvailability_iface
.lpVtbl
= &async_user_consent_verifier_availability_vtbl
;
498 if (FAILED(hr
= async_info_create( invoker
, param
, callback
, (IInspectable
*)&impl
->IAsyncOperation_UserConsentVerifierAvailability_iface
, &impl
->IWineAsyncInfoImpl_inner
)) ||
499 FAILED(hr
= IWineAsyncInfoImpl_Start( impl
->IWineAsyncInfoImpl_inner
)))
501 if (impl
->IWineAsyncInfoImpl_inner
) IWineAsyncInfoImpl_Release( impl
->IWineAsyncInfoImpl_inner
);
506 *out
= &impl
->IAsyncOperation_UserConsentVerifierAvailability_iface
;
507 TRACE( "created IAsyncOperation_UserConsentVerifierAvailability %p\n", *out
);