-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Background and Motivation
The SafeHandle type was designed around an assumption that the runtime could manage all aspects of its lifetime. The source generation proposal pushed this responsible onto a third party tool (i.e. Roslyn source generator). In order to better support that scenario, the following APIs are proposed to help with SafeHandle manipulation.
Proposed API
Update guidance here to indicate derived types would need a public default constructor. This proposal would include ensuring all SafeHandle implementations provided by .NET follow this guidance.
Microsoft.Win32.SafeHandles.SafeAccessTokenHandleMicrosoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalidSystem.Net.Sockets.SafeSocketHandleMicrosoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalidMicrosoft.Win32.SafeHandles.SafeFileHandleMicrosoft.Win32.SafeHandles.SafeMemoryMappedFileHandleMicrosoft.Win32.SafeHandles.SafeNCryptHandleMicrosoft.Win32.SafeHandles.SafePipeHandleMicrosoft.Win32.SafeHandles.SafeProcessHandleMicrosoft.Win32.SafeHandles.SafeRegistryHandleMicrosoft.Win32.SafeHandles.SafeWaitHandleMicrosoft.Win32.SafeHandles.SafeX509ChainHandleSystem.Runtime.InteropServices.SafeBufferSystem.Security.Authentication.ExtendedProtection.ChannelBindingSystem.Security.Cryptography.SafeEvpPKeyHandle
Expose SetHandle as a public API so source generators may call it.
See #45633 (comment).
Usage Examples
Usage example would the ability to call SetHandle and instantiate any type derived from SafeHandle so they can be used from a source generator.
Alternative Designs
Expose static functions for SafeHandle manipulation.
namespace System.Runtime.InteropServices
{
public static class Marshal
{
+ /// <summary>
+ /// Create an instance of the given <typeparamref name="TSafeHandle"/>.
+ /// </summary>
+ /// <typeparam name="TSafeHandle">Type of the SafeHandle</typeparam>
+ /// <returns>New instance of <typeparamref name="TSafeHandle"/></returns>
+ /// <remarks>
+ /// The <typeparamref name="TSafeHandle"/> must be non-abstract and have a parameterless constructor.
+ /// </remarks>
+ public static TSafeHandle CreateSafeHandle<
+ [DynamicallyAccessedMembers(
+ DynamicallyAccessedMemberTypes.PublicParameterlessConstructor
+ | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
+ TSafeHandle>() where TSafeHandle : SafeHandle;
+ /// <summary>
+ /// Sets the handle of <paramref name="safeHandle"/> to the specified <paramref name="handle"/>.
+ /// </summary>
+ /// <param name="safeHandle"><see cref="SafeHandle"/> instance to update</param>
+ /// <param name="handle">Pre-existing handle</param>
+ public static void SetHandle(SafeHandle safeHandle, IntPtr handle);
}
}Risks
Low. These APIs expose internal lifetime operations that users have often wanted to hide. This is however mitigated by the fact that using reflection these "hidden" APIs can be used regardless.