Definition for SDK projection / object model#40121
Definition for SDK projection / object model#40121florelis wants to merge 2 commits intomicrosoft:feature/wsl-for-appsfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a proposed WinRT (MIDL 3) object model for the WSLC SDK intended to enable a natural C# projection (e.g., via CsWinRT) without raw pointers/handles.
Changes:
- Introduces a new WinRT IDL describing Sessions, Containers, Processes, and related settings/options types as runtimeclasses/enums/delegates.
- Replaces several handle/callback-style patterns with WinRT-friendly constructs (streams, events/delegates, factory methods).
- Defines supporting types for install/version reporting and image progress reporting.
| Crashed = 2, | ||
| }; | ||
|
|
||
| delegate void SessionTerminationHandler(Session session, SessionTerminationReason reason); |
There was a problem hiding this comment.
I changed "Callback" to "Handler" because I think that's more idiomatic in C#
| void PullImage(PullImageOptions options); | ||
|
|
||
| // C# equivalent type: System.IO.StreamReader | ||
| void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, ImportImageOptions options); |
There was a problem hiding this comment.
The C API uses a HANDLE for the image content. I changed it to a stream based on what I understood from how it's used, but I may be wrong.
| UInt16 ContainerPort { get; }; | ||
| PortProtocol Protocol { get; }; | ||
|
|
||
| // TODO sockaddr_storage* WindowsAddress { get; set; }; |
There was a problem hiding this comment.
This one I didn't know how to map, so I left it as a TODO for now.
| IVector<String> CmdLine { get; set; }; | ||
| // C# equivalent type: System.Collections.Specialized.StringDictionary | ||
| // C# projected type: System.Collections.Generic.IDictionary<string,string?> | ||
| IMap<String, String> EnvironmentVariables { get; set; }; |
There was a problem hiding this comment.
This is an array of strings in the C API. I changed it to match the C# Process type.
| // C# equivalent Windowstype: System.IO.StreamReader | ||
| Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle); | ||
| // C# type: System.IO.StreamWriter | ||
| Windows.Storage.Streams.IOutputStream GetInputStream(); |
There was a problem hiding this comment.
These are a single function in the C API. For WinRT there is no generic Stream type that can do both AFAICT, but if we do direct C# implementation it can be a System.IO.Stream and a single function to match.
| // C# equivalent type: System.Collections.Specialized.StringDictionary | ||
| // C# projected type: System.Collections.Generic.IDictionary<string,string?> |
There was a problem hiding this comment.
C# equivalent type: What we could use if we define it in C# directly.
C# projected type: What we would get if we use CsWinRT to get a projection from the .idl.
|
|
||
| UInt32 CpuCount { get; set; }; | ||
| UInt32 MemoryMb { get; set; }; | ||
| UInt32 TimeoutMS { get; set; }; |
There was a problem hiding this comment.
TimeoutMS uses a different casing convention than the other properties (MemoryMb, CpuCount). For C# projections this will surface as an awkward TimeoutMS property name. Consider using consistent PascalCase with standard abbreviations (e.g., TimeoutMs) to align with the rest of this IDL and typical .NET naming.
| UInt32 TimeoutMS { get; set; }; | |
| UInt32 TimeoutMs { get; set; }; |
| runtimeclass RegistryAuthenticationInformation | ||
| { | ||
| // TBD | ||
| String Placeholder {get; set;}; |
There was a problem hiding this comment.
RegistryAuthenticationInformation currently exposes a Placeholder property. If this IDL is intended to be a public SDK surface, shipping a placeholder member is likely to become a breaking-change trap when real auth fields are introduced. Consider either omitting AuthInfo until the shape is defined, or defining a minimal but real contract (e.g., auth scheme + token/username/password) now.
| runtimeclass RegistryAuthenticationInformation | |
| { | |
| // TBD | |
| String Placeholder {get; set;}; | |
| enum RegistryAuthenticationScheme | |
| { | |
| None = 0, | |
| Basic = 1, | |
| BearerToken = 2, | |
| }; | |
| runtimeclass RegistryAuthenticationInformation | |
| { | |
| RegistryAuthenticationScheme Scheme { get; set; }; | |
| String Username { get; set; }; | |
| String Password { get; set; }; | |
| String Token { get; set; }; |
| // C# projected type: System.Collections.Generic.IDictionary<string,string?> | ||
| IMap<String, String> EnvironmentVariables { get; set; }; | ||
| ProcessEventHandlers EventHandlers { get; set; }; | ||
| }; |
There was a problem hiding this comment.
The API exposes both callback-style process I/O (ProcessSettings.EventHandlers) and stream-style I/O (Process.GetOutputStream/GetInputStream). In the existing C SDK these are mutually exclusive (callbacks consume the stdio handles), so the WinRT surface should either enforce the same exclusivity (fail fast if streams are requested when handlers are set) or clearly document which takes precedence to avoid surprising runtime failures.
| void PullImage(PullImageOptions options); | ||
|
|
||
| // C# type: System.IO.Stream | ||
| void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, ImportImageOptions options); |
There was a problem hiding this comment.
ImportImage only takes an IInputStream, but the underlying WSLC APIs require a content length (COM IWSLCSession::ImportImage takes ContentLength). IInputStream doesn’t reliably expose length, so implementations may be forced to buffer the entire stream. Consider using a size-bearing WinRT type (e.g., IRandomAccessStream/IRandomAccessStreamReference) or add an explicit UInt64 contentLength parameter.
| void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, ImportImageOptions options); | |
| void ImportImage(String imageName, Windows.Storage.Streams.IInputStream imageStream, UInt64 contentLength, ImportImageOptions options); |
| void ImportImageFromFile(String imageName, String path, ImportImageOptions options); | ||
|
|
||
| // C# type: System.IO.Stream | ||
| void LoadImage(Windows.Storage.Streams.IInputStream imageStream, LoadImageOptions options); |
There was a problem hiding this comment.
LoadImage only takes an IInputStream, but the underlying WSLC APIs require a content length (COM IWSLCSession::LoadImage takes ContentLength). IInputStream doesn’t reliably expose length, so implementations may be forced to buffer the entire stream. Consider using a size-bearing WinRT type (e.g., IRandomAccessStream/IRandomAccessStreamReference) or add an explicit UInt64 contentLength parameter.
| void LoadImage(Windows.Storage.Streams.IInputStream imageStream, LoadImageOptions options); | |
| void LoadImage(Windows.Storage.Streams.IInputStream imageStream, UInt64 contentLength, LoadImageOptions options); |
| // C# type: System.IO.Stream | ||
| Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle); | ||
| // C# type: System.IO.Stream |
There was a problem hiding this comment.
The comments indicate these methods project to System.IO.Stream, but the WinRT signatures return IInputStream/IOutputStream. Unless your projection layer adds custom adapters, CsWinRT will surface WinRT stream interfaces here, so the comment may be inaccurate. Consider clarifying in the comment how .NET callers should obtain a Stream (or adjust the API surface accordingly).
| // C# type: System.IO.Stream | |
| Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle); | |
| // C# type: System.IO.Stream | |
| // C# projected type: Windows.Storage.Streams.IInputStream | |
| // .NET callers can adapt this to System.IO.Stream using the standard WinRT stream extension methods if needed. | |
| Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle); | |
| // C# projected type: Windows.Storage.Streams.IOutputStream | |
| // .NET callers can adapt this to System.IO.Stream using the standard WinRT stream extension methods if needed. |
| Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle); | ||
| // C# type: System.IO.Stream | ||
| Windows.Storage.Streams.IOutputStream GetInputStream(); |
There was a problem hiding this comment.
GetOutputStream returns an IInputStream (read end) and GetInputStream returns an IOutputStream (write end). The names are easy to misread as “stream you write output to” vs “stream you read input from”. Consider renaming to make direction explicit (e.g., GetStdOutStream/GetStdErrStream/GetStdInStream) so callers don’t accidentally invert read/write usage.
| Windows.Storage.Streams.IInputStream GetOutputStream(ProcessOutputHandle ioHandle); | |
| // C# type: System.IO.Stream | |
| Windows.Storage.Streams.IOutputStream GetInputStream(); | |
| Windows.Storage.Streams.IInputStream GetStandardIoOutputReader(ProcessOutputHandle ioHandle); | |
| // C# type: System.IO.Stream | |
| Windows.Storage.Streams.IOutputStream GetStandardInputWriter(); |
|
|
||
| Module Name: | ||
|
|
||
| wslcsdk.idl |
There was a problem hiding this comment.
Header comment has Module Name: wslcsdk.idl, but the file is wslcsdk-winrt.idl. Consider updating the module name to match the actual filename to avoid confusion when this is referenced in build/scripts.
| wslcsdk.idl | |
| wslcsdk-winrt.idl |
This is a proposal for a projection / object model for the SDK API, specifically intended for the C# projection.
It is written in MIDL 3, which means it represents a WinRT interface, but everything maps directly to C# so it should still allow us to talk about the design of the interface.
This is more or less a direct translation of the C header.
structs to classes.Session) to a staticCreate()factory method to avoid having constructors that may throw (and in case we ever want to have an async variant).Release()functions.WslcGetProcessIOHandle()into two functions to be able to return properly typed input/output streams.This interface could be implemented in C++ as WinRT, and then using CsWinRT we can get a pretty natural C# projection with no or minimal changes. That would allow us to not have to deal with raw pointers and having to pin data from C#.