CLR via C#:与WinRT组件互操作

    技术2022-07-11  103

    基础知识:如下所示: 1.WinRT组件使用由ECMA协会标准化的.NET元数据格式(ECMA-335)来描述其API,这些元数据会嵌入到扩展名为.winmd的文件中。 2.RCW(运行时可调用包装器)内部引用了WinRT组件。 3.CCW(COM可调用包装器)内部引用了CLR对象。

    CLR投射:CLR通过元数据将WinRT类型隐式投射成FCL类型。

    框架投射:CLR通过代码将WinRT类型显式投射成FCL类型。具有以下特性: 1.可以使用WindowsRuntimeSystemExtensions类中的辅助函数来完成.NET异步调用WinRT。 2.可以使用WindowsRuntimeStorageExtensions和WindowsRuntimeStreamExtensions类中的辅助函数来完成.NET和WinRT之间互传输数据流。 3.可以使用WindowsRuntimeBufferExtensions类中的辅助函数来完成.NET和WinRT之间传输数据块。

    用C#定义WinRT组件:具有以下特性: 1.使用该WinRT组件时,一般会造成的额外性能损失和内存消耗。 2.使用ildasm的/project命令开关可以查看将WinRT类型投射成FCL等价类型之后的元数据。 3.C#实现WinRT组件的模板如下所示:

    using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading; using System.Threading.Tasks; using Windows.Foundation; using Windows.Foundation.Metadata; // The namespace MUST match the assembly name and cannot be "Windows" namespace LearnCLR.WinRTComponents { // [Flags] // Must not be present if enum is int; required if enum is uint public enum WinRTEnum : int { // Enums must be backed by int or uint None, NotNone } // Structures can only contain core data types, String, & other structures // No constructors or methods are allowed public struct WinRTStruct { public Int32 ANumber; public String AString; public WinRTEnum AEnum; // Really just a 32-bit integer } // Delegates must have WinRT-compatible types in the signature (no BeginInvoke/EndInvoke) public delegate String WinRTDelegate(Int32 x); // Interfaces can have methods, properties, & events but cannot be generic. public interface IWinRTInterface { // Nullable<T> marshals as IReference<T> Int32? InterfaceProperty { get; set; } } // Members without a [Version(#)] attribute default to the class's // version (1) and are part of the same underlying COM interface // produced by WinMDExp.exe. [Version(1)] // Class must be derived from Object, sealed, not generic, // implement only WinRT interfaces, & public members must be WinRT types public sealed class WinRTClass : IWinRTInterface { // Public fields are not allowed #region Class can expose static methods, properties, and events public static String StaticMethod(String s) { return "Returning " + s; } public static WinRTStruct StaticProperty { get; set; } // In JavaScript 'out' parameters are returned as objects with each // parameter becoming a property along with the return value public static String OutParameters(out WinRTStruct x, out Int32 year) { x = new WinRTStruct { AEnum = WinRTEnum.NotNone, ANumber = 333, AString = "Jeff" }; year = DateTimeOffset.Now.Year; return "Grant"; } #endregion // Constructor can take arguments but not out/ref arguments public WinRTClass(Int32? number) { InterfaceProperty = number; } public Int32? InterfaceProperty { get; set; } // Only ToString is allowed to be overridden public override String ToString() { return String.Format("InterfaceProperty={0}", InterfaceProperty.HasValue ? InterfaceProperty.Value.ToString() : "(not set)"); } public void ThrowingMethod() { throw new InvalidOperationException("My exception message"); // To throw a specific HRESULT, use COMException instead //const Int32 COR_E_INVALIDOPERATION = unchecked((Int32)0x80131509); //throw new COMException("Invalid Operation", COR_E_INVALIDOPERATION); } #region Arrays are passed, returned OR filled; never a combination public Int32 PassArray([ReadOnlyArray] /* [In] implied */ Int32[] data) { // NOTE: Modified array contents MAY not be marshaled out; do not modify the array return data.Sum(); } public Int32 FillArray([WriteOnlyArray] /* [Out] implied */ Int32[] data) { // NOTE: Original array contents MAY not be marshaled in; // write to the array before reading from it for (Int32 n = 0; n < data.Length; n++) data[n] = n; return data.Length; } public Int32[] ReturnArray() { // Array is marshaled out upon return return new Int32[] { 1, 2, 3 }; } #endregion // Collections are passed by reference public void PassAndModifyCollection(IDictionary<String, Object> collection) { collection["Key2"] = "Value2"; // Modifies collection in place via interop } #region Method overloading // Overloads with same # of parameters are considered identical to JavaScript public void SomeMethod(Int32 x) { } [Windows.Foundation.Metadata.DefaultOverload] // Attribute makes this method the default overload public void SomeMethod(String s) { } #endregion #region Automatically implemented event public event WinRTDelegate AutoEvent; public String RaiseAutoEvent(Int32 number) { WinRTDelegate d = AutoEvent; return (d == null) ? "No callbacks registered" : d(number); } #endregion #region Manually implemented event // Private field that keeps track of the event's registered delegates private EventRegistrationTokenTable<WinRTDelegate> m_manualEvent = null; // Manual implementation of the event's add and remove methods public event WinRTDelegate ManualEvent { add { // Gets the existing table, or creates a new one if the table is not yet initialized return EventRegistrationTokenTable<WinRTDelegate> .GetOrCreateEventRegistrationTokenTable(ref m_manualEvent).AddEventHandler(value); } remove { EventRegistrationTokenTable<WinRTDelegate> .GetOrCreateEventRegistrationTokenTable(ref m_manualEvent).RemoveEventHandler(value); } } public String RaiseManualEvent(Int32 number) { WinRTDelegate d = EventRegistrationTokenTable<WinRTDelegate> .GetOrCreateEventRegistrationTokenTable(ref m_manualEvent).InvocationList; return (d == null) ? "No callbacks registered" : d(number); } #endregion #region Asynchronous methods // Async methods MUST return IAsync[Action|Operation](WithProgress) // NOTE: Other languages see the DataTimeOffset as Windows.Foundation.DateTime public IAsyncOperationWithProgress<DateTimeOffset, Int32> DoSomethingAsync() { // Use the System.Runtime.InteropServices.WindowsRuntime.AsyncInfo's Run methods to // invoke a private method written entirely in managed code return AsyncInfo.Run<DateTimeOffset, Int32>(DoSomethingAsyncInternal); } // Implement the async operation via a private method using normal .NET technologies private async Task<DateTimeOffset> DoSomethingAsyncInternal( CancellationToken ct, IProgress<Int32> progress) { for (Int32 x = 0; x < 10; x++) { // This code supports cancellation and progress reporting ct.ThrowIfCancellationRequested(); if (progress != null) progress.Report(x * 10); await Task.Delay(1000); // Simulate doing something asynchronously } return DateTimeOffset.Now; // Ultimate return value } public IAsyncOperation<DateTimeOffset> DoSomethingAsync2() { // If you don't need cancellation & progress, use // System.WindowsRuntimeSystemExtensions' AsAsync[Action|Operation] Task // extension methods (these call AsyncInfo.Run internally) return DoSomethingAsyncInternal(default(CancellationToken), null).AsAsyncOperation(); } #endregion // After you ship a version, mark new members with a [Version(#)] attribute // so that WinMDExp.exe puts the new members in a different underlying COM // interface. This is required since COM interfaces are supposed to be immutable. [Version(2)] public void NewMethodAddedInV2() { } } }
    Processed: 0.011, SQL: 9