1 /* CryptoWinRT 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
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(crypto
);
28 #define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0)
32 IWineAsyncInfoImpl IWineAsyncInfoImpl_iface
;
33 IAsyncInfo IAsyncInfo_iface
;
34 IInspectable
*IInspectable_outer
;
37 async_operation_callback callback
;
38 TP_WORK
*async_run_work
;
43 IWineAsyncOperationCompletedHandler
*handler
;
49 static inline struct async_info
*impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl
*iface
)
51 return CONTAINING_RECORD( iface
, struct async_info
, IWineAsyncInfoImpl_iface
);
54 static HRESULT WINAPI
async_impl_QueryInterface( IWineAsyncInfoImpl
*iface
, REFIID iid
, void **out
)
56 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
58 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
60 if (IsEqualGUID( iid
, &IID_IUnknown
) ||
61 IsEqualGUID( iid
, &IID_IInspectable
) ||
62 IsEqualGUID( iid
, &IID_IAgileObject
) ||
63 IsEqualGUID( iid
, &IID_IWineAsyncInfoImpl
))
65 IInspectable_AddRef( (*out
= &impl
->IWineAsyncInfoImpl_iface
) );
69 if (IsEqualGUID( iid
, &IID_IAsyncInfo
))
71 IInspectable_AddRef( (*out
= &impl
->IAsyncInfo_iface
) );
75 FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid
) );
80 static ULONG WINAPI
async_impl_AddRef( IWineAsyncInfoImpl
*iface
)
82 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
83 ULONG ref
= InterlockedIncrement( &impl
->ref
);
84 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
88 static ULONG WINAPI
async_impl_Release( IWineAsyncInfoImpl
*iface
)
90 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
91 ULONG ref
= InterlockedDecrement( &impl
->ref
);
92 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
96 if (impl
->handler
&& impl
->handler
!= HANDLER_NOT_SET
) IWineAsyncOperationCompletedHandler_Release( impl
->handler
);
97 IAsyncInfo_Close( &impl
->IAsyncInfo_iface
);
98 if (impl
->param
) IUnknown_Release( impl
->param
);
99 if (impl
->invoker
) IUnknown_Release( impl
->invoker
);
100 impl
->cs
.DebugInfo
->Spare
[0] = 0;
101 DeleteCriticalSection( &impl
->cs
);
108 static HRESULT WINAPI
async_impl_put_Completed( IWineAsyncInfoImpl
*iface
, IWineAsyncOperationCompletedHandler
*handler
)
110 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
113 TRACE( "iface %p, handler %p.\n", iface
, handler
);
115 EnterCriticalSection( &impl
->cs
);
116 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
117 else if (impl
->handler
!= HANDLER_NOT_SET
) hr
= E_ILLEGAL_DELEGATE_ASSIGNMENT
;
118 else if ((impl
->handler
= handler
))
120 IWineAsyncOperationCompletedHandler_AddRef( impl
->handler
);
122 if (impl
->status
> Started
)
124 IInspectable
*operation
= impl
->IInspectable_outer
;
125 AsyncStatus status
= impl
->status
;
126 impl
->handler
= NULL
; /* Prevent concurrent invoke. */
127 LeaveCriticalSection( &impl
->cs
);
129 IWineAsyncOperationCompletedHandler_Invoke( handler
, operation
, status
);
130 IWineAsyncOperationCompletedHandler_Release( handler
);
135 LeaveCriticalSection( &impl
->cs
);
140 static HRESULT WINAPI
async_impl_get_Completed( IWineAsyncInfoImpl
*iface
, IWineAsyncOperationCompletedHandler
**handler
)
142 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
145 TRACE( "iface %p, handler %p.\n", iface
, handler
);
147 EnterCriticalSection( &impl
->cs
);
148 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
149 if (impl
->handler
== NULL
|| impl
->handler
== HANDLER_NOT_SET
) *handler
= NULL
;
150 else IWineAsyncOperationCompletedHandler_AddRef( (*handler
= impl
->handler
) );
151 LeaveCriticalSection( &impl
->cs
);
156 static HRESULT WINAPI
async_impl_get_Result( IWineAsyncInfoImpl
*iface
, PROPVARIANT
*result
)
158 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
159 HRESULT hr
= E_ILLEGAL_METHOD_CALL
;
161 TRACE( "iface %p, result %p.\n", iface
, result
);
163 EnterCriticalSection( &impl
->cs
);
164 if (impl
->status
== Completed
|| impl
->status
== Error
)
166 PropVariantCopy( result
, &impl
->result
);
169 LeaveCriticalSection( &impl
->cs
);
174 static HRESULT WINAPI
async_impl_Start( IWineAsyncInfoImpl
*iface
)
176 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
178 TRACE( "iface %p.\n", iface
);
180 /* keep the async alive in the callback */
181 IInspectable_AddRef( impl
->IInspectable_outer
);
182 SubmitThreadpoolWork( impl
->async_run_work
);
187 static const struct IWineAsyncInfoImplVtbl async_impl_vtbl
=
189 /* IUnknown methods */
190 async_impl_QueryInterface
,
193 /* IWineAsyncInfoImpl */
194 async_impl_put_Completed
,
195 async_impl_get_Completed
,
196 async_impl_get_Result
,
200 DEFINE_IINSPECTABLE_OUTER( async_info
, IAsyncInfo
, struct async_info
, IInspectable_outer
)
202 static HRESULT WINAPI
async_info_get_Id( IAsyncInfo
*iface
, UINT32
*id
)
204 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
207 TRACE( "iface %p, id %p.\n", iface
, id
);
209 EnterCriticalSection( &impl
->cs
);
210 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
212 LeaveCriticalSection( &impl
->cs
);
217 static HRESULT WINAPI
async_info_get_Status( IAsyncInfo
*iface
, AsyncStatus
*status
)
219 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
222 TRACE( "iface %p, status %p.\n", iface
, status
);
224 EnterCriticalSection( &impl
->cs
);
225 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
226 *status
= impl
->status
;
227 LeaveCriticalSection( &impl
->cs
);
232 static HRESULT WINAPI
async_info_get_ErrorCode( IAsyncInfo
*iface
, HRESULT
*error_code
)
234 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
237 TRACE( "iface %p, error_code %p.\n", iface
, error_code
);
239 EnterCriticalSection( &impl
->cs
);
240 if (impl
->status
== Closed
) *error_code
= hr
= E_ILLEGAL_METHOD_CALL
;
241 else *error_code
= impl
->hr
;
242 LeaveCriticalSection( &impl
->cs
);
247 static HRESULT WINAPI
async_info_Cancel( IAsyncInfo
*iface
)
249 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
252 TRACE( "iface %p.\n", iface
);
254 EnterCriticalSection( &impl
->cs
);
255 if (impl
->status
== Closed
) hr
= E_ILLEGAL_METHOD_CALL
;
256 else if (impl
->status
== Started
) impl
->status
= Canceled
;
257 LeaveCriticalSection( &impl
->cs
);
262 static HRESULT WINAPI
async_info_Close( IAsyncInfo
*iface
)
264 struct async_info
*impl
= impl_from_IAsyncInfo( iface
);
267 TRACE( "iface %p.\n", iface
);
269 EnterCriticalSection( &impl
->cs
);
270 if (impl
->status
== Started
)
271 hr
= E_ILLEGAL_STATE_CHANGE
;
272 else if (impl
->status
!= Closed
)
274 CloseThreadpoolWork( impl
->async_run_work
);
275 impl
->async_run_work
= NULL
;
276 impl
->status
= Closed
;
278 LeaveCriticalSection( &impl
->cs
);
283 static const struct IAsyncInfoVtbl async_info_vtbl
=
285 /* IUnknown methods */
286 async_info_QueryInterface
,
289 /* IInspectable methods */
291 async_info_GetRuntimeClassName
,
292 async_info_GetTrustLevel
,
295 async_info_get_Status
,
296 async_info_get_ErrorCode
,
301 static void CALLBACK
async_info_callback( TP_CALLBACK_INSTANCE
*instance
, void *iface
, TP_WORK
*work
)
303 struct async_info
*impl
= impl_from_IWineAsyncInfoImpl( iface
);
304 IInspectable
*operation
= impl
->IInspectable_outer
;
308 hr
= impl
->callback( impl
->invoker
, impl
->param
, &result
);
310 EnterCriticalSection( &impl
->cs
);
311 if (impl
->status
!= Closed
) impl
->status
= FAILED(hr
) ? Error
: Completed
;
312 PropVariantCopy( &impl
->result
, &result
);
315 if (impl
->handler
!= NULL
&& impl
->handler
!= HANDLER_NOT_SET
)
317 IWineAsyncOperationCompletedHandler
*handler
= impl
->handler
;
318 AsyncStatus status
= impl
->status
;
319 impl
->handler
= NULL
; /* Prevent concurrent invoke. */
320 LeaveCriticalSection( &impl
->cs
);
322 IWineAsyncOperationCompletedHandler_Invoke( handler
, operation
, status
);
323 IWineAsyncOperationCompletedHandler_Release( handler
);
325 else LeaveCriticalSection( &impl
->cs
);
327 /* release refcount acquired in Start */
328 IInspectable_Release( operation
);
330 PropVariantClear( &result
);
333 static HRESULT
async_info_create( IUnknown
*invoker
, IUnknown
*param
, async_operation_callback callback
,
334 IInspectable
*outer
, IWineAsyncInfoImpl
**out
)
336 struct async_info
*impl
;
339 if (!(impl
= calloc( 1, sizeof(struct async_info
) ))) return E_OUTOFMEMORY
;
340 impl
->IWineAsyncInfoImpl_iface
.lpVtbl
= &async_impl_vtbl
;
341 impl
->IAsyncInfo_iface
.lpVtbl
= &async_info_vtbl
;
342 impl
->IInspectable_outer
= outer
;
345 impl
->callback
= callback
;
346 impl
->handler
= HANDLER_NOT_SET
;
347 impl
->status
= Started
;
348 if (!(impl
->async_run_work
= CreateThreadpoolWork( async_info_callback
, &impl
->IWineAsyncInfoImpl_iface
, NULL
)))
350 hr
= HRESULT_FROM_WIN32( GetLastError() );
355 if ((impl
->invoker
= invoker
)) IUnknown_AddRef( impl
->invoker
);
356 if ((impl
->param
= param
)) IUnknown_AddRef( impl
->param
);
358 InitializeCriticalSection( &impl
->cs
);
359 impl
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)( __FILE__
": async_info.cs" );
361 *out
= &impl
->IWineAsyncInfoImpl_iface
;
367 IAsyncOperation_boolean IAsyncOperation_boolean_iface
;
368 IWineAsyncInfoImpl
*IWineAsyncInfoImpl_inner
;
372 static inline struct async_bool
*impl_from_IAsyncOperation_boolean( IAsyncOperation_boolean
*iface
)
374 return CONTAINING_RECORD( iface
, struct async_bool
, IAsyncOperation_boolean_iface
);
377 static HRESULT WINAPI
async_bool_QueryInterface( IAsyncOperation_boolean
*iface
, REFIID iid
, void **out
)
379 struct async_bool
*impl
= impl_from_IAsyncOperation_boolean( iface
);
381 TRACE( "iface %p, iid %s, out %p.\n", iface
, debugstr_guid( iid
), out
);
383 if (IsEqualGUID( iid
, &IID_IUnknown
) ||
384 IsEqualGUID( iid
, &IID_IInspectable
) ||
385 IsEqualGUID( iid
, &IID_IAgileObject
) ||
386 IsEqualGUID( iid
, &IID_IAsyncOperation_boolean
))
388 IInspectable_AddRef( (*out
= &impl
->IAsyncOperation_boolean_iface
) );
392 return IWineAsyncInfoImpl_QueryInterface( impl
->IWineAsyncInfoImpl_inner
, iid
, out
);
395 static ULONG WINAPI
async_bool_AddRef( IAsyncOperation_boolean
*iface
)
397 struct async_bool
*impl
= impl_from_IAsyncOperation_boolean( iface
);
398 ULONG ref
= InterlockedIncrement( &impl
->ref
);
399 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
403 static ULONG WINAPI
async_bool_Release( IAsyncOperation_boolean
*iface
)
405 struct async_bool
*impl
= impl_from_IAsyncOperation_boolean( iface
);
406 ULONG ref
= InterlockedDecrement( &impl
->ref
);
407 TRACE( "iface %p, ref %lu.\n", iface
, ref
);
411 /* guard against re-entry if inner releases an outer iface */
412 InterlockedIncrement( &impl
->ref
);
413 IWineAsyncInfoImpl_Release( impl
->IWineAsyncInfoImpl_inner
);
420 static HRESULT WINAPI
async_bool_GetIids( IAsyncOperation_boolean
*iface
, ULONG
*iid_count
, IID
**iids
)
422 FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
426 static HRESULT WINAPI
async_bool_GetRuntimeClassName( IAsyncOperation_boolean
*iface
, HSTRING
*class_name
)
428 return WindowsCreateString( L
"Windows.Foundation.IAsyncOperation`1<Boolean>",
429 ARRAY_SIZE(L
"Windows.Foundation.IAsyncOperation`1<Boolean>"),
433 static HRESULT WINAPI
async_bool_GetTrustLevel( IAsyncOperation_boolean
*iface
, TrustLevel
*trust_level
)
435 FIXME( "iface %p, trust_level %p stub!\n", iface
, trust_level
);
439 static HRESULT WINAPI
async_bool_put_Completed( IAsyncOperation_boolean
*iface
, IAsyncOperationCompletedHandler_boolean
*bool_handler
)
441 IWineAsyncOperationCompletedHandler
*handler
= (IWineAsyncOperationCompletedHandler
*)bool_handler
;
442 struct async_bool
*impl
= impl_from_IAsyncOperation_boolean( 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_bool_get_Completed( IAsyncOperation_boolean
*iface
, IAsyncOperationCompletedHandler_boolean
**bool_handler
)
449 IWineAsyncOperationCompletedHandler
**handler
= (IWineAsyncOperationCompletedHandler
**)bool_handler
;
450 struct async_bool
*impl
= impl_from_IAsyncOperation_boolean( iface
);
451 TRACE( "iface %p, handler %p.\n", iface
, handler
);
452 return IWineAsyncInfoImpl_get_Completed( impl
->IWineAsyncInfoImpl_inner
, (IWineAsyncOperationCompletedHandler
**)handler
);
455 static HRESULT WINAPI
async_bool_GetResults( IAsyncOperation_boolean
*iface
, BOOLEAN
*results
)
457 struct async_bool
*impl
= impl_from_IAsyncOperation_boolean( iface
);
458 PROPVARIANT result
= {.vt
= VT_BOOL
};
461 TRACE( "iface %p, results %p.\n", iface
, results
);
463 hr
= IWineAsyncInfoImpl_get_Result( impl
->IWineAsyncInfoImpl_inner
, &result
);
465 *results
= result
.boolVal
;
466 PropVariantClear( &result
);
470 static const struct IAsyncOperation_booleanVtbl async_bool_vtbl
=
472 /* IUnknown methods */
473 async_bool_QueryInterface
,
476 /* IInspectable methods */
478 async_bool_GetRuntimeClassName
,
479 async_bool_GetTrustLevel
,
480 /* IAsyncOperation<boolean> */
481 async_bool_put_Completed
,
482 async_bool_get_Completed
,
483 async_bool_GetResults
,
486 HRESULT
async_operation_boolean_create( IUnknown
*invoker
, IUnknown
*param
, async_operation_callback callback
,
487 IAsyncOperation_boolean
**out
)
489 struct async_bool
*impl
;
493 if (!(impl
= calloc( 1, sizeof(*impl
) ))) return E_OUTOFMEMORY
;
494 impl
->IAsyncOperation_boolean_iface
.lpVtbl
= &async_bool_vtbl
;
497 if (FAILED(hr
= async_info_create( invoker
, param
, callback
, (IInspectable
*)&impl
->IAsyncOperation_boolean_iface
, &impl
->IWineAsyncInfoImpl_inner
)) ||
498 FAILED(hr
= IWineAsyncInfoImpl_Start( impl
->IWineAsyncInfoImpl_inner
)))
500 if (impl
->IWineAsyncInfoImpl_inner
) IWineAsyncInfoImpl_Release( impl
->IWineAsyncInfoImpl_inner
);
505 *out
= &impl
->IAsyncOperation_boolean_iface
;
506 TRACE( "created IAsyncOperation_boolean %p\n", *out
);