A wrapper source generator for WinRT
- C# ISO-2 or later
- Add the NuGet package
WinRTWrapperto your project. - Find a class or interface that you want to wrap for WinRT. For example, let's say you have a simple class like this:
publicsealedclassSimple{publicintProperty{get;set;}publicintMethod()=>Property;publicTaskMethodAsync()=>Task.CompletedTask;publicTaskMethodWithTokenAsync(CancellationTokencancellationToken)=>Task.CompletedTask;publiceventEventHandler<int>?Event;}
- Add the
GenerateWinRTWrapperattribute to your class or interface that you want to wrap.[GenerateWinRTWrapper(typeof(Simple))]publicsealedpartialclassSimpleWrapper;
- The source generator will automatically generate a WinRT wrapper for the specified class or interface. You can then use this wrapper in your WinRT applications.
// <auto-generated/> #pragma warning disable /// <inheritdoc cref="T:Simple"/>publicsealedpartialclassSimpleWrapper{/// <summary>/// The target <see cref="T:Simple"/> object of the wrapper./// </summary>privatereadonlyglobal::WinRTWrapper.Test.Simpletarget;/// <summary>/// Initializes a new instance of the <see cref="T:SimpleWrapper"/> class with the specified target <see cref="T:Simple"/> object./// </summary>/// <param name="target">The target <see cref="T:Simple"/> object.</param>internalSimpleWrapper(global::WinRTWrapper.Test.Simpletarget){this.target=target;}/// <inheritdoc cref="P:Simple.Property"/>publicintProperty{get{returnthis.target.Property;}set{this.target.Property=value;}}/// <inheritdoc cref="M:Simple.Method"/>publicintMethod(){returnthis.target.Method();}/// <inheritdoc cref="M:Simple.MethodAsync"/>publicglobal::Windows.Foundation.IAsyncActionMethodAsync(){returnglobal::System.WindowsRuntimeSystemExtensions.AsAsyncAction(this.target.MethodAsync());}/// <inheritdoc cref="M:Simple.MethodWithTokenAsync(System.Threading.CancellationToken)"/>publicglobal::Windows.Foundation.IAsyncActionMethodWithTokenAsync(){returnglobal::System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run(delegate(global::System.Threading.CancellationTokencancellationToken){returnthis.target.MethodWithTokenAsync(cancellationToken);});}/// <inheritdoc cref="E:Simple.Event"/>publiceventglobal::System.EventHandler<int>Event{add{this.target.Event+=value;}remove{this.target.Event-=value;}}}
You can specify which types of members to generate in the wrapper class by add parameters to the GenerateWinRTWrapper attribute. For example, GenerateMember.Interface will only generate interface members:
[GenerateWinRTWrapper(typeof(Simple),GenerateMember.Interface)]publicsealedpartialclassSimpleWrapper:I;GenerateMember.Defined will only generate members that are defined in the class:
[GenerateWinRTWrapper(typeof(Simple),GenerateMember.Defined)]publicsealedpartialclassSimpleWrapper{publicpartialintMethod();publicstaticpartialSimpleWrapperGetSelf(SimpleWrapperself);}You can also specify interfaces which not implemented in the class as a filter:
[GenerateWinRTWrapper(typeof(Simple),typeof(I))]publicsealedpartialclassSimpleWrapper;You can define a custom marshaller for a specific type by WinRTWrapperMarshaller attribute. A marshaller should implement ConvertToWrapper and ConvertToManaged methods. For example:
[WinRTWrapperMarshaller(typeof(Simple),typeof(SimpleWrapper))]publicsealedpartialclassSimpleWrapper{/// <summary>/// Converts a managed type <see cref="T:WinRTWrapper.Test.Simple"/> to a wrapper type <see cref="T:WinRTWrapper.Test.SimpleWrapper"/>./// </summary>/// <param name="managed">The managed type to convert.</param>/// <returns>The converted wrapper type.</returns>internalstaticglobal::WinRTWrapper.Test.SimpleWrapperConvertToWrapper(global::WinRTWrapper.Test.Simplemanaged){return(global::WinRTWrapper.Test.SimpleWrapper)newglobal::WinRTWrapper.Test.SimpleWrapper(managed);}/// <summary>/// Converts a wrapper type <see cref="T:WinRTWrapper.Test.SimpleWrapper"/> to a managed type <see cref="T:WinRTWrapper.Test.Simple"/>./// </summary>/// <param name="wrapper">The wrapper type to convert.</param>/// <returns>The converted managed type.</returns>internalstaticglobal::WinRTWrapper.Test.SimpleConvertToManaged(global::WinRTWrapper.Test.SimpleWrapperwrapper){return(global::WinRTWrapper.Test.Simple)((global::WinRTWrapper.Test.SimpleWrapper)wrapper).target;}}It will be generated automatically when both WinRTWrapperMarshaller and GenerateWinRTWrapper attributes are applied to the same class.
Then you can use the WinRTWrapperMarshalUsing attribute to specify the marshaller for a method parameter or return value.
You can apply it to the managed type:
/// <summary>/// Gets a new instance of the <see cref="Simple"/> class with the specified value./// </summary>/// <param name="self">The value to initialize the instance with.</param>/// <returns>The new instance of <see cref="Simple"/>.</returns>[return:WinRTWrapperMarshalUsing(typeof(SimpleWrapper))]publicstaticSimpleGetSelf([WinRTWrapperMarshalUsing(typeof(SimpleWrapper))]Simpleself){returnself;}Or you can apply it to the wrapper type:
[return:WinRTWrapperMarshalUsing(typeof(SimpleWrapper))]publicstaticpartialSimpleWrapperGetSelf([WinRTWrapperMarshalUsing(typeof(SimpleWrapper))]SimpleWrapperself);You can also use the WinRTWrapperMarshalling attribute to specify the marshaller for a class.
[WinRTWrapperMarshalling(typeof(SimpleWrapper))]internalclassSimple;Since C#/WinRT is not IL/WinRT, you should define every members in the wrapper class. So that the C#/WinRT can generate the correct WinRT metadata for the wrapper class.