diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/.gitignore b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/.gitignore new file mode 100644 index 000000000..a374dd6be --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/.gitignore @@ -0,0 +1,16 @@ +# Ignore directories +bin/ +obj/ + +# Ignore files +*.user +*.userosscache +*.suo +*.userprefs +*.dll +*.exe +*.pdb +*.cache +*.vsp +*.vspx +*.sap diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/App.axaml b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/App.axaml new file mode 100644 index 000000000..f807f50e9 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/App.axaml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/App.axaml.cs b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/App.axaml.cs new file mode 100644 index 000000000..23f0f0dc1 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/App.axaml.cs @@ -0,0 +1,24 @@ +using System; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; + +namespace Devolutions.IronRdp.AvaloniaExample; + +public partial class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow(); + } + + base.OnFrameworkInitializationCompleted(); + } +} \ No newline at end of file diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj new file mode 100644 index 000000000..d358f1e4c --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj @@ -0,0 +1,21 @@ + + + WinExe + net8.0 + enable + true + app.manifest + true + true + + + + + + + + + + + + diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.sln b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.sln new file mode 100644 index 000000000..dc1a353ba --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devolutions.IronRdp.AvaloniaExample", "Devolutions.IronRdp.AvaloniaExample.csproj", "{B374556F-70F4-4B70-90AE-6DF00C532240}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B374556F-70F4-4B70-90AE-6DF00C532240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B374556F-70F4-4B70-90AE-6DF00C532240}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B374556F-70F4-4B70-90AE-6DF00C532240}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B374556F-70F4-4B70-90AE-6DF00C532240}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1DD5DE59-5AB4-4F5F-A2AC-CA4D7012F56E} + EndGlobalSection +EndGlobal diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/KeyCodeMapper.cs b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/KeyCodeMapper.cs new file mode 100644 index 000000000..b94824579 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/KeyCodeMapper.cs @@ -0,0 +1,104 @@ +using Avalonia.Input; +using System; +using System.Collections.Generic; + +public static class KeyCodeMapper +{ + private static readonly Dictionary KeyToScancodeMap = new Dictionary + { + {PhysicalKey.Escape, 0x01}, + {PhysicalKey.Digit1, 0x02}, + {PhysicalKey.Digit2, 0x03}, + {PhysicalKey.Digit3, 0x04}, + {PhysicalKey.Digit4, 0x05}, + {PhysicalKey.Digit5, 0x06}, + {PhysicalKey.Digit6, 0x07}, + {PhysicalKey.Digit7, 0x08}, + {PhysicalKey.Digit8, 0x09}, + {PhysicalKey.Digit9, 0x0A}, + {PhysicalKey.Digit0, 0x0B}, + {PhysicalKey.Minus, 0x0C}, + {PhysicalKey.Equal, 0x0D}, + {PhysicalKey.Backspace, 0x0E}, + {PhysicalKey.Tab, 0x0F}, + {PhysicalKey.Q, 0x10}, + {PhysicalKey.W, 0x11}, + {PhysicalKey.E, 0x12}, + {PhysicalKey.R, 0x13}, + {PhysicalKey.T, 0x14}, + {PhysicalKey.Y, 0x15}, + {PhysicalKey.U, 0x16}, + {PhysicalKey.I, 0x17}, + {PhysicalKey.O, 0x18}, + {PhysicalKey.P, 0x19}, + {PhysicalKey.BracketLeft, 0x1A}, + {PhysicalKey.BracketRight, 0x1B}, + {PhysicalKey.Enter, 0x1C}, + {PhysicalKey.ControlLeft, 0x1D}, + {PhysicalKey.A, 0x1E}, + {PhysicalKey.S, 0x1F}, + {PhysicalKey.D, 0x20}, + {PhysicalKey.F, 0x21}, + {PhysicalKey.G, 0x22}, + {PhysicalKey.H, 0x23}, + {PhysicalKey.J, 0x24}, + {PhysicalKey.K, 0x25}, + {PhysicalKey.L, 0x26}, + {PhysicalKey.Semicolon, 0x27}, + {PhysicalKey.Quote, 0x28}, + {PhysicalKey.ShiftLeft, 0x2A}, + {PhysicalKey.Backslash, 0x2B}, + {PhysicalKey.Z, 0x2C}, + {PhysicalKey.X, 0x2D}, + {PhysicalKey.C, 0x2E}, + {PhysicalKey.V, 0x2F}, + {PhysicalKey.B, 0x30}, + {PhysicalKey.N, 0x31}, + {PhysicalKey.M, 0x32}, + {PhysicalKey.Comma, 0x33}, + {PhysicalKey.Period, 0x34}, + {PhysicalKey.Slash, 0x35}, + {PhysicalKey.ShiftRight, 0x36}, + {PhysicalKey.PrintScreen, 0x37}, + {PhysicalKey.AltLeft, 0x38}, + {PhysicalKey.Space, 0x39}, + {PhysicalKey.CapsLock, 0x3A}, + {PhysicalKey.F1, 0x3B}, + {PhysicalKey.F2, 0x3C}, + {PhysicalKey.F3, 0x3D}, + {PhysicalKey.F4, 0x3E}, + {PhysicalKey.F5, 0x3F}, + {PhysicalKey.F6, 0x40}, + {PhysicalKey.F7, 0x41}, + {PhysicalKey.F8, 0x42}, + {PhysicalKey.F9, 0x43}, + {PhysicalKey.F10, 0x44}, + {PhysicalKey.NumLock, 0x45}, + {PhysicalKey.ScrollLock, 0x46}, + {PhysicalKey.Home, 0x47}, + {PhysicalKey.ArrowUp, 0x48}, + {PhysicalKey.PageUp, 0x49}, + {PhysicalKey.NumPadSubtract, 0x4A}, + {PhysicalKey.ArrowLeft, 0x4B}, + {PhysicalKey.NumPad5, 0x4C}, + {PhysicalKey.ArrowRight, 0x4D}, + {PhysicalKey.NumPadAdd, 0x4E}, + {PhysicalKey.End, 0x4F}, + {PhysicalKey.ArrowDown, 0x50}, + {PhysicalKey.PageDown, 0x51}, + {PhysicalKey.Insert, 0x52}, + {PhysicalKey.Delete, 0x53}, + {PhysicalKey.F11, 0x57}, + {PhysicalKey.F12, 0x58} + }; + + + public static ushort? GetScancode(PhysicalKey key) + { + if (KeyToScancodeMap.TryGetValue(key, out ushort scancode)) + { + return scancode; + } + return null; + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml new file mode 100644 index 000000000..71a325e2c --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs new file mode 100644 index 000000000..75720d1e0 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs @@ -0,0 +1,273 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Threading; +using System; +using System.Diagnostics; +using System.Net.Security; +using System.Threading.Tasks; + +namespace Devolutions.IronRdp.AvaloniaExample; + +public partial class MainWindow : Window +{ + + WriteableBitmap? bitmap; + Canvas? canvas; + Image? image; + InputDatabase? inputDatabase = InputDatabase.New(); + ActiveStage? activeStage; + DecodedImage? decodedImage; + Framed? framed; + public MainWindow() + { + InitializeComponent(); + this.Opened += OnOpened; + + } + + private void OnOpened(object? sender, EventArgs e) + { + WindowState = WindowState.Maximized; + + var username = Environment.GetEnvironmentVariable("IRONRDP_USERNAME"); + var password = Environment.GetEnvironmentVariable("IRONRDP_PASSWORD"); + var domain = Environment.GetEnvironmentVariable("IRONRDP_DOMAIN"); + var server = Environment.GetEnvironmentVariable("IRONRDP_SERVER"); + + if (username == null || password == null || domain == null || server == null) + { + Trace.TraceError("Please set the IRONRDP_USERNAME, IRONRDP_PASSWORD, IRONRDP_DOMAIN, and IRONRDP_SERVER environment variables"); + Close(); + return; + } + + var width = 1280; + var height = 800; + + var config = buildConfig(username, password, domain, width, height); + + var task = Connection.Connect(config, server); + bitmap = new WriteableBitmap(new PixelSize(width, height), new Vector(96, 96), Avalonia.Platform.PixelFormat.Rgba8888, AlphaFormat.Opaque); + canvas = this.FindControl("MainCanvas")!; + canvas.Focusable = true; + image = new Image { Width = width, Height = height, Source = this.bitmap }; + canvas.Children.Add(image); + + canvas.KeyDown += Canvas_KeyDown; + canvas.KeyUp += Canvas_KeyUp; + + task.ContinueWith(t => + { + if (t.IsFaulted) + { + Exception e = t.Exception!; + Trace.TraceError("Error connecting to server: " + e.Message); + Close(); + return; + } + var (res, framed) = t.Result; + this.decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(), res.GetDesktopSize().GetHeight()); + this.activeStage = ActiveStage.New(res); + this.framed = framed; + ReadPduAndProcessActiveStage(); + }); + } + + private async void WriteDecodedImageToCanvas() + { + await Dispatcher.UIThread.InvokeAsync(() => + { + var data = decodedImage!.GetData(); + var bufferSize = (int)data.GetSize(); + + var buffer = new byte[bufferSize]; + data.Fill(buffer); + + using (var bitmap = this.bitmap!.Lock()) + { + unsafe + { + var bitmapSpan = new Span((void*)bitmap.Address, bufferSize); + var bufferSpan = new Span(buffer); + bufferSpan.CopyTo(bitmapSpan); + } + } + + image!.InvalidateVisual(); + }); + } + + + + + private void ReadPduAndProcessActiveStage() + { + Task.Run(async () => + { + var keepLooping = true; + while (keepLooping) + { + var readPduTask = await framed!.ReadPdu(); + Action action = readPduTask.Item1; + byte[] payload = readPduTask.Item2; + var outputIterator = activeStage!.Process(decodedImage!, action, payload); + keepLooping = await HandleActiveStageOutput(outputIterator); + } + }); + } + + private static Config buildConfig(string username, string password, string domain, int width, int height) + { + ConfigBuilder configBuilder = ConfigBuilder.New(); + + configBuilder.WithUsernameAndPassword(username, password); + configBuilder.SetDomain(domain); + configBuilder.SetDesktopSize((ushort)height, (ushort)width); + configBuilder.SetClientName("IronRdp"); + configBuilder.SetClientDir("C:\\"); + configBuilder.SetPerformanceFlags(PerformanceFlags.NewDefault()); + + return configBuilder.Build(); + } + + private void Canvas_OnPointerPressed(object sender, Avalonia.Input.PointerPressedEventArgs e) + { + PointerUpdateKind mouseButton = e.GetCurrentPoint((Visual?)sender).Properties.PointerUpdateKind; + + MouseButtonType buttonType = mouseButton switch + { + PointerUpdateKind.LeftButtonPressed => MouseButtonType.Left, + PointerUpdateKind.RightButtonPressed => MouseButtonType.Right, + PointerUpdateKind.MiddleButtonPressed => MouseButtonType.Middle, + PointerUpdateKind.XButton1Pressed => MouseButtonType.X1, + PointerUpdateKind.XButton2Pressed => MouseButtonType.X2, + PointerUpdateKind.LeftButtonReleased => MouseButtonType.Left, + PointerUpdateKind.MiddleButtonReleased => MouseButtonType.Middle, + PointerUpdateKind.RightButtonReleased => MouseButtonType.Right, + PointerUpdateKind.XButton1Released => MouseButtonType.X1, + PointerUpdateKind.XButton2Released => MouseButtonType.X2, + PointerUpdateKind.Other => throw new NotImplementedException(), + _ => throw new NotImplementedException(), + }; + + var buttonOperation = MouseButton.New(buttonType).AsOperationMouseButtonPressed(); + var fastpath = inputDatabase!.Apply(buttonOperation); + var output = activeStage!.ProcessFastpathInput(decodedImage!, fastpath); + var _ = HandleActiveStageOutput(output); + } + + private void Canvas_PointerMoved(object sender, PointerEventArgs e) + { + if (this.activeStage == null || this.decodedImage == null) + { + return; + } + var position = e.GetPosition((Visual?)sender); + var x = (ushort)position.X; + var y = (ushort)position.Y; + var mouseMovedEvent = MousePosition.New(x, y).AsMoveOperation(); + var fastpath = inputDatabase!.Apply(mouseMovedEvent); + var output = activeStage.ProcessFastpathInput(decodedImage, fastpath); + var _ = HandleActiveStageOutput(output); + } + + private void Canvas_PointerReleased(object sender, PointerReleasedEventArgs e) + { + PointerUpdateKind mouseButton = e.GetCurrentPoint((Visual?)sender).Properties.PointerUpdateKind; + + MouseButtonType buttonType = mouseButton switch + { + PointerUpdateKind.LeftButtonPressed => MouseButtonType.Left, + PointerUpdateKind.RightButtonPressed => MouseButtonType.Right, + PointerUpdateKind.MiddleButtonPressed => MouseButtonType.Middle, + PointerUpdateKind.XButton1Pressed => MouseButtonType.X1, + PointerUpdateKind.XButton2Pressed => MouseButtonType.X2, + PointerUpdateKind.LeftButtonReleased => MouseButtonType.Left, + PointerUpdateKind.MiddleButtonReleased => MouseButtonType.Middle, + PointerUpdateKind.RightButtonReleased => MouseButtonType.Right, + PointerUpdateKind.XButton1Released => MouseButtonType.X1, + PointerUpdateKind.XButton2Released => MouseButtonType.X2, + PointerUpdateKind.Other => throw new NotImplementedException(), + _ => throw new NotImplementedException(), + }; + + var buttonOperation = MouseButton.New(buttonType).AsOperationMouseButtonReleased(); + var fastpath = inputDatabase!.Apply(buttonOperation); + var output = activeStage!.ProcessFastpathInput(decodedImage!, fastpath); + var _ = HandleActiveStageOutput(output); + } + + private void Canvas_KeyDown(object? sender, KeyEventArgs? e) + { + if (activeStage == null || decodedImage == null) + { + return; + } + PhysicalKey physicalKey = e!.PhysicalKey; + + var keyOperation = Scancode.FromU16((ushort)KeyCodeMapper.GetScancode(physicalKey)!).AsOperationKeyPressed(); + var fastpath = inputDatabase!.Apply(keyOperation); + var output = activeStage.ProcessFastpathInput(decodedImage, fastpath); + var _ = HandleActiveStageOutput(output); + } + + private void Canvas_KeyUp(object? sender, KeyEventArgs? e) + { + if (this.activeStage == null || this.decodedImage == null) + { + return; + } + Key key = e!.Key; + var keyOperation = Scancode.FromU16((ushort)key).AsOperationKeyReleased(); + var fastpath = inputDatabase!.Apply(keyOperation); + var output = activeStage.ProcessFastpathInput(decodedImage, fastpath); + var _ = HandleActiveStageOutput(output); + } + + private async Task HandleActiveStageOutput(ActiveStageOutputIterator outputIterator) + { + try + { + + while (!outputIterator.IsEmpty()) + { + var output = outputIterator.Next()!; // outputIterator.Next() is not null since outputIterator.IsEmpty() is false + if (output.GetEnumType() == ActiveStageOutputType.Terminate) + { + return false; + } + else if (output.GetEnumType() == ActiveStageOutputType.ResponseFrame) + { + // render the decoded image to canvas + WriteDecodedImageToCanvas(); + // Send the response frame to the server + var responseFrame = output.GetResponseFrame()!; + byte[] responseFrameBytes = new byte[responseFrame.GetSize()]; + responseFrame.Fill(responseFrameBytes); + await framed!.Write(responseFrameBytes); + } + else if (output.GetEnumType() == ActiveStageOutputType.GraphicsUpdate) + { + WriteDecodedImageToCanvas(); + } + else if (output.GetEnumType() == ActiveStageOutputType.PointerPosition) + { + WriteDecodedImageToCanvas(); + } + else if (output.GetEnumType() == ActiveStageOutputType.PointerBitmap) + { + WriteDecodedImageToCanvas(); + } + } + return true; + } + catch (Exception e) + { + return false; + } + } + +} diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Program.cs b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Program.cs new file mode 100644 index 000000000..1d0ce255d --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Program.cs @@ -0,0 +1,38 @@ +using Avalonia; +using System; +using System.Diagnostics; + +namespace Devolutions.IronRdp.AvaloniaExample; + +class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) + { + InitializeLogging(); + try{ + BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + }catch(Exception e){ + Trace.TraceError(e.Message); + } + } + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); + + public static void InitializeLogging() + { + Trace.AutoFlush = true; + TextWriterTraceListener myListener = new TextWriterTraceListener(System.IO.File.CreateText("AvaloniaExample.log")); + Trace.Listeners.Add(myListener); + } + +} diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/app.manifest b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/app.manifest new file mode 100644 index 000000000..62829436e --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.sln b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.sln new file mode 100644 index 000000000..3f6a119b0 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devolutions.IronRdp.ConnectExample", "Devolutions.IronRdp.ConnectExample.csproj", "{EB812E03-EDBE-4576-A84A-A26982D46BE1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EB812E03-EDBE-4576-A84A-A26982D46BE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB812E03-EDBE-4576-A84A-A26982D46BE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB812E03-EDBE-4576-A84A-A26982D46BE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB812E03-EDBE-4576-A84A-A26982D46BE1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C47D6FCB-C82B-4C07-AA17-839B0B0CF0D2} + EndGlobalSection +EndGlobal diff --git a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs index 3be56f89c..2d4d8c817 100644 --- a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs +++ b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs @@ -47,13 +47,13 @@ static async Task Main(string[] args) { var output = outputIterator.Next()!; // outputIterator.Next() is not null since outputIterator.IsEmpty() is false Console.WriteLine($"Output type: {output.GetType()}"); - if (output.GetType() == ActiveStageOutputType.Terminate) + if (output.GetEnumType() == ActiveStageOutputType.Terminate) { Console.WriteLine("Connection terminated."); keepLooping = false; } - if (output.GetType() == ActiveStageOutputType.ResponseFrame) + if (output.GetEnumType() == ActiveStageOutputType.ResponseFrame) { var responseFrame = output.GetResponseFrame()!; byte[] responseFrameBytes = new byte[responseFrame.GetSize()]; diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStage.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStage.cs index ed32efa1c..105e06c11 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStage.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStage.cs @@ -91,6 +91,40 @@ public ActiveStageOutputIterator Process(DecodedImage image, Action action, byte } } + /// + /// + /// A ActiveStageOutputIterator allocated on Rust side. + /// + public ActiveStageOutputIterator ProcessFastpathInput(DecodedImage image, FastPathInputEventIterator fastpathInput) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("ActiveStage"); + } + Raw.DecodedImage* imageRaw; + imageRaw = image.AsFFI(); + if (imageRaw == null) + { + throw new ObjectDisposedException("DecodedImage"); + } + Raw.FastPathInputEventIterator* fastpathInputRaw; + fastpathInputRaw = fastpathInput.AsFFI(); + if (fastpathInputRaw == null) + { + throw new ObjectDisposedException("FastPathInputEventIterator"); + } + Raw.SessionFfiResultBoxActiveStageOutputIteratorBoxIronRdpError result = Raw.ActiveStage.ProcessFastpathInput(_inner, imageRaw, fastpathInputRaw); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.ActiveStageOutputIterator* retVal = result.Ok; + return new ActiveStageOutputIterator(retVal); + } + } + /// /// Returns the underlying raw handle. /// diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStageOutput.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStageOutput.cs index 4bc7022b3..44e407576 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStageOutput.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/ActiveStageOutput.cs @@ -23,6 +23,14 @@ public ConnectionActivationSequence DeactivateAll } } + public ActiveStageOutputType EnumType + { + get + { + return GetEnumType(); + } + } + public InclusiveRectangle GraphicsUpdate { get @@ -63,14 +71,6 @@ public GracefulDisconnectReason Terminate } } - public ActiveStageOutputType Type - { - get - { - return GetType(); - } - } - /// /// Creates a managed ActiveStageOutput from a raw handle. /// @@ -88,7 +88,7 @@ public unsafe ActiveStageOutput(Raw.ActiveStageOutput* handle) /// /// A ActiveStageOutputType allocated on C# side. /// - public ActiveStageOutputType GetType() + public ActiveStageOutputType GetEnumType() { unsafe { @@ -96,7 +96,7 @@ public ActiveStageOutputType GetType() { throw new ObjectDisposedException("ActiveStageOutput"); } - Raw.ActiveStageOutputType retVal = Raw.ActiveStageOutput.GetType(_inner); + Raw.ActiveStageOutputType retVal = Raw.ActiveStageOutput.GetEnumType(_inner); return (ActiveStageOutputType)retVal; } } diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/BitmapConfig.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/BitmapConfig.cs new file mode 100644 index 000000000..e3d932525 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/BitmapConfig.cs @@ -0,0 +1,63 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class BitmapConfig: IDisposable +{ + private unsafe Raw.BitmapConfig* _inner; + + /// + /// Creates a managed BitmapConfig from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe BitmapConfig(Raw.BitmapConfig* handle) + { + _inner = handle; + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.BitmapConfig* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.BitmapConfig.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~BitmapConfig() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/Char.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/Char.cs new file mode 100644 index 000000000..41b58453a --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/Char.cs @@ -0,0 +1,113 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class Char: IDisposable +{ + private unsafe Raw.Char* _inner; + + /// + /// Creates a managed Char from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe Char(Raw.Char* handle) + { + _inner = handle; + } + + /// + /// + /// A Char allocated on Rust side. + /// + public static Char New(uint c) + { + unsafe + { + Raw.InputFfiResultBoxCharBoxIronRdpError result = Raw.Char.New(c); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.Char* retVal = result.Ok; + return new Char(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperationUnicodeKeyPressed() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("Char"); + } + Raw.Operation* retVal = Raw.Char.AsOperationUnicodeKeyPressed(_inner); + return new Operation(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperationUnicodeKeyReleased() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("Char"); + } + Raw.Operation* retVal = Raw.Char.AsOperationUnicodeKeyReleased(_inner); + return new Operation(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.Char* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.Char.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~Char() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/ClientConnectorState.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/ClientConnectorState.cs index 1b4b692df..ba2bb0301 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/ClientConnectorState.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/ClientConnectorState.cs @@ -39,6 +39,14 @@ public ConnectionResult ConnectedResult } } + public ConnectionActivationSequence ConnectionFinalizationResult + { + get + { + return GetConnectionFinalizationResult(); + } + } + public SecurityProtocol ConnectionInitiationWaitConfirmRequestedProtocol { get @@ -63,11 +71,11 @@ public SecurityProtocol EnhancedSecurityUpgradeSelectedProtocol } } - public ClientConnectorStateType Type + public ClientConnectorStateType EnumType { get { - return GetType(); + return GetEnumType(); } } @@ -89,7 +97,7 @@ public unsafe ClientConnectorState(Raw.ClientConnectorState* handle) /// /// A ClientConnectorStateType allocated on C# side. /// - public ClientConnectorStateType GetType() + public ClientConnectorStateType GetEnumType() { unsafe { @@ -97,7 +105,7 @@ public ClientConnectorStateType GetType() { throw new ObjectDisposedException("ClientConnectorState"); } - Raw.ConnectorStateFfiResultClientConnectorStateTypeBoxIronRdpError result = Raw.ClientConnectorState.GetType(_inner); + Raw.ConnectorStateFfiResultClientConnectorStateTypeBoxIronRdpError result = Raw.ClientConnectorState.GetEnumType(_inner); if (!result.isOk) { throw new IronRdpException(new IronRdpError(result.Err)); @@ -239,6 +247,28 @@ public ConnectionResult GetConnectedResult() } } + /// + /// + /// A ConnectionActivationSequence allocated on Rust side. + /// + public ConnectionActivationSequence GetConnectionFinalizationResult() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("ClientConnectorState"); + } + Raw.ConnectorStateFfiResultBoxConnectionActivationSequenceBoxIronRdpError result = Raw.ClientConnectorState.GetConnectionFinalizationResult(_inner); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.ConnectionActivationSequence* retVal = result.Ok; + return new ConnectionActivationSequence(retVal); + } + } + /// /// Returns the underlying raw handle. /// diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/ConfigBuilder.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/ConfigBuilder.cs index f821ebfb3..92a20977e 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/ConfigBuilder.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/ConfigBuilder.cs @@ -23,6 +23,14 @@ public bool Autologon } } + public BitmapConfig BitmapConfig + { + set + { + SetBitmapConfig(value); + } + } + public uint ClientBuild { set @@ -326,6 +334,24 @@ public void SetPerformanceFlags(PerformanceFlags performanceFlags) } } + public void SetBitmapConfig(BitmapConfig bitmap) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("ConfigBuilder"); + } + Raw.BitmapConfig* bitmapRaw; + bitmapRaw = bitmap.AsFFI(); + if (bitmapRaw == null) + { + throw new ObjectDisposedException("BitmapConfig"); + } + Raw.ConfigBuilder.SetBitmapConfig(_inner, bitmapRaw); + } + } + public void SetClientBuild(uint clientBuild) { unsafe diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/DiplomatRuntime.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/DiplomatRuntime.cs index 158688dd6..18223e37b 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/DiplomatRuntime.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/DiplomatRuntime.cs @@ -46,11 +46,11 @@ public DiplomatWriteable() IntPtr flushFuncPtr = Marshal.GetFunctionPointerForDelegate(flushFunc); IntPtr growFuncPtr = Marshal.GetFunctionPointerForDelegate(growFunc); - + // flushFunc and growFunc are managed objects and might be disposed of by the garbage collector. // To prevent this, we make the context hold the references and protect the context itself // for automatic disposal by moving it behind a GCHandle. - DiplomatWriteableContext ctx = new DiplomatWriteableContext(); + DiplomatWriteableContext ctx = new DiplomatWriteableContext(); ctx.flushFunc = flushFunc; ctx.growFunc = growFunc; GCHandle ctxHandle = GCHandle.Alloc(ctx); @@ -81,7 +81,7 @@ public string ToUnicode() { throw new IndexOutOfRangeException("DiplomatWriteable buffer is too big"); } - return Marshal.PtrToStringUTF8(buf, (int)len); + return Marshal.PtrToStringUTF8(buf, (int) len); #else byte[] utf8 = ToUtf8Bytes(); return DiplomatUtils.Utf8ToString(utf8); diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/FastPathInputEvent.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/FastPathInputEvent.cs new file mode 100644 index 000000000..2323938f4 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/FastPathInputEvent.cs @@ -0,0 +1,63 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class FastPathInputEvent: IDisposable +{ + private unsafe Raw.FastPathInputEvent* _inner; + + /// + /// Creates a managed FastPathInputEvent from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe FastPathInputEvent(Raw.FastPathInputEvent* handle) + { + _inner = handle; + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.FastPathInputEvent* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.FastPathInputEvent.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~FastPathInputEvent() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/FastPathInputEventIterator.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/FastPathInputEventIterator.cs new file mode 100644 index 000000000..e68281465 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/FastPathInputEventIterator.cs @@ -0,0 +1,63 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class FastPathInputEventIterator: IDisposable +{ + private unsafe Raw.FastPathInputEventIterator* _inner; + + /// + /// Creates a managed FastPathInputEventIterator from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe FastPathInputEventIterator(Raw.FastPathInputEventIterator* handle) + { + _inner = handle; + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.FastPathInputEventIterator* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.FastPathInputEventIterator.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~FastPathInputEventIterator() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/InputDatabase.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/InputDatabase.cs index fc59c3da7..d754dd559 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/InputDatabase.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/InputDatabase.cs @@ -41,6 +41,28 @@ public static InputDatabase New() } } + /// + /// A FastPathInputEventIterator allocated on Rust side. + /// + public FastPathInputEventIterator Apply(Operation operation) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("InputDatabase"); + } + Raw.Operation* operationRaw; + operationRaw = operation.AsFFI(); + if (operationRaw == null) + { + throw new ObjectDisposedException("Operation"); + } + Raw.FastPathInputEventIterator* retVal = Raw.InputDatabase.Apply(_inner, operationRaw); + return new FastPathInputEventIterator(retVal); + } + } + /// /// Returns the underlying raw handle. /// diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/MouseButton.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/MouseButton.cs new file mode 100644 index 000000000..70dee4bdb --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/MouseButton.cs @@ -0,0 +1,109 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class MouseButton: IDisposable +{ + private unsafe Raw.MouseButton* _inner; + + /// + /// Creates a managed MouseButton from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe MouseButton(Raw.MouseButton* handle) + { + _inner = handle; + } + + /// + /// A MouseButton allocated on Rust side. + /// + public static MouseButton New(MouseButtonType button) + { + unsafe + { + Raw.MouseButtonType buttonRaw; + buttonRaw = (Raw.MouseButtonType)button; + Raw.MouseButton* retVal = Raw.MouseButton.New(buttonRaw); + return new MouseButton(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperationMouseButtonPressed() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("MouseButton"); + } + Raw.Operation* retVal = Raw.MouseButton.AsOperationMouseButtonPressed(_inner); + return new Operation(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperationMouseButtonReleased() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("MouseButton"); + } + Raw.Operation* retVal = Raw.MouseButton.AsOperationMouseButtonReleased(_inner); + return new Operation(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.MouseButton* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.MouseButton.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~MouseButton() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/MouseButtonType.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/MouseButtonType.cs new file mode 100644 index 000000000..e84e07518 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/MouseButtonType.cs @@ -0,0 +1,21 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public enum MouseButtonType +{ + Left = 0, + Middle = 1, + Right = 2, + X1 = 3, + X2 = 4, +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/MousePosition.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/MousePosition.cs new file mode 100644 index 000000000..daf15e364 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/MousePosition.cs @@ -0,0 +1,91 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class MousePosition: IDisposable +{ + private unsafe Raw.MousePosition* _inner; + + /// + /// Creates a managed MousePosition from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe MousePosition(Raw.MousePosition* handle) + { + _inner = handle; + } + + /// + /// A MousePosition allocated on Rust side. + /// + public static MousePosition New(ushort x, ushort y) + { + unsafe + { + Raw.MousePosition* retVal = Raw.MousePosition.New(x, y); + return new MousePosition(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsMoveOperation() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("MousePosition"); + } + Raw.Operation* retVal = Raw.MousePosition.AsMoveOperation(_inner); + return new Operation(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.MousePosition* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.MousePosition.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~MousePosition() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/Operation.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/Operation.cs new file mode 100644 index 000000000..a7a3dcd21 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/Operation.cs @@ -0,0 +1,63 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class Operation: IDisposable +{ + private unsafe Raw.Operation* _inner; + + /// + /// Creates a managed Operation from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe Operation(Raw.Operation* handle) + { + _inner = handle; + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.Operation* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.Operation.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~Operation() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/OperationType.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/OperationType.cs new file mode 100644 index 000000000..553542410 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/OperationType.cs @@ -0,0 +1,24 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public enum OperationType +{ + MouseButtonPressed = 0, + MouseButtonReleased = 1, + MouseMove = 2, + WheelRotations = 3, + KeyPressed = 4, + KeyReleased = 5, + UnicodeKeyPressed = 6, + UnicodeKeyReleased = 7, +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStage.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStage.cs index a0f3d27ee..ddda9e5e1 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStage.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStage.cs @@ -22,6 +22,9 @@ public partial struct ActiveStage [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ActiveStage_process", ExactSpelling = true)] public static unsafe extern SessionFfiResultBoxActiveStageOutputIteratorBoxIronRdpError Process(ActiveStage* self, DecodedImage* image, Action* action, byte* payload, nuint payloadSz); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ActiveStage_process_fastpath_input", ExactSpelling = true)] + public static unsafe extern SessionFfiResultBoxActiveStageOutputIteratorBoxIronRdpError ProcessFastpathInput(ActiveStage* self, DecodedImage* image, FastPathInputEventIterator* fastpathInput); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ActiveStage_destroy", ExactSpelling = true)] public static unsafe extern void Destroy(ActiveStage* self); } diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStageOutput.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStageOutput.cs index 5aa25a44a..a39a90147 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStageOutput.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawActiveStageOutput.cs @@ -16,8 +16,8 @@ public partial struct ActiveStageOutput { private const string NativeLib = "DevolutionsIronRdp"; - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ActiveStageOutput_get_type", ExactSpelling = true)] - public static unsafe extern ActiveStageOutputType GetType(ActiveStageOutput* self); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ActiveStageOutput_get_enum_type", ExactSpelling = true)] + public static unsafe extern ActiveStageOutputType GetEnumType(ActiveStageOutput* self); [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ActiveStageOutput_get_response_frame", ExactSpelling = true)] public static unsafe extern SessionFfiResultBoxBytesSliceBoxIronRdpError GetResponseFrame(ActiveStageOutput* self); diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawBitmapConfig.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawBitmapConfig.cs new file mode 100644 index 000000000..0cfede60a --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawBitmapConfig.cs @@ -0,0 +1,21 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct BitmapConfig +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "BitmapConfig_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(BitmapConfig* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawChar.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawChar.cs new file mode 100644 index 000000000..6e12c8b00 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawChar.cs @@ -0,0 +1,30 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct Char +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Char_new", ExactSpelling = true)] + public static unsafe extern InputFfiResultBoxCharBoxIronRdpError New(uint c); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Char_as_operation_unicode_key_pressed", ExactSpelling = true)] + public static unsafe extern Operation* AsOperationUnicodeKeyPressed(Char* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Char_as_operation_unicode_key_released", ExactSpelling = true)] + public static unsafe extern Operation* AsOperationUnicodeKeyReleased(Char* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Char_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(Char* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawClientConnectorState.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawClientConnectorState.cs index 06e1dd417..57c4abe0d 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawClientConnectorState.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawClientConnectorState.cs @@ -16,8 +16,8 @@ public partial struct ClientConnectorState { private const string NativeLib = "DevolutionsIronRdp"; - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ClientConnectorState_get_type", ExactSpelling = true)] - public static unsafe extern ConnectorStateFfiResultClientConnectorStateTypeBoxIronRdpError GetType(ClientConnectorState* self); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ClientConnectorState_get_enum_type", ExactSpelling = true)] + public static unsafe extern ConnectorStateFfiResultClientConnectorStateTypeBoxIronRdpError GetEnumType(ClientConnectorState* self); [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ClientConnectorState_get_connection_initiation_wait_confirm_requested_protocol", ExactSpelling = true)] public static unsafe extern ConnectorStateFfiResultBoxSecurityProtocolBoxIronRdpError GetConnectionInitiationWaitConfirmRequestedProtocol(ClientConnectorState* self); @@ -37,6 +37,9 @@ public partial struct ClientConnectorState [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ClientConnectorState_get_connected_result", ExactSpelling = true)] public static unsafe extern ConnectorStateFfiResultBoxConnectionResultBoxIronRdpError GetConnectedResult(ClientConnectorState* self); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ClientConnectorState_get_connection_finalization_result", ExactSpelling = true)] + public static unsafe extern ConnectorStateFfiResultBoxConnectionActivationSequenceBoxIronRdpError GetConnectionFinalizationResult(ClientConnectorState* self); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ClientConnectorState_destroy", ExactSpelling = true)] public static unsafe extern void Destroy(ClientConnectorState* self); } diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawConfigBuilder.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawConfigBuilder.cs index 08a19c4ef..e369260dd 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawConfigBuilder.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawConfigBuilder.cs @@ -52,6 +52,9 @@ public partial struct ConfigBuilder [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ConfigBuilder_set_performance_flags", ExactSpelling = true)] public static unsafe extern void SetPerformanceFlags(ConfigBuilder* self, PerformanceFlags* performanceFlags); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ConfigBuilder_set_bitmap_config", ExactSpelling = true)] + public static unsafe extern void SetBitmapConfig(ConfigBuilder* self, BitmapConfig* bitmap); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ConfigBuilder_set_client_build", ExactSpelling = true)] public static unsafe extern void SetClientBuild(ConfigBuilder* self, uint clientBuild); diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawConnectorStateFfiResultBoxConnectionActivationSequenceBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawConnectorStateFfiResultBoxConnectionActivationSequenceBoxIronRdpError.cs new file mode 100644 index 000000000..0523d083f --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawConnectorStateFfiResultBoxConnectionActivationSequenceBoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct ConnectorStateFfiResultBoxConnectionActivationSequenceBoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal ConnectionActivationSequence* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe ConnectionActivationSequence* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawFastPathInputEvent.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawFastPathInputEvent.cs new file mode 100644 index 000000000..b64183050 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawFastPathInputEvent.cs @@ -0,0 +1,21 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct FastPathInputEvent +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "FastPathInputEvent_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(FastPathInputEvent* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawFastPathInputEventIterator.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawFastPathInputEventIterator.cs new file mode 100644 index 000000000..df9c1617e --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawFastPathInputEventIterator.cs @@ -0,0 +1,21 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct FastPathInputEventIterator +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "FastPathInputEventIterator_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(FastPathInputEventIterator* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputDatabase.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputDatabase.cs index b1699ddec..712591cd0 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputDatabase.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputDatabase.cs @@ -19,6 +19,9 @@ public partial struct InputDatabase [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "InputDatabase_new", ExactSpelling = true)] public static unsafe extern InputDatabase* New(); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "InputDatabase_apply", ExactSpelling = true)] + public static unsafe extern FastPathInputEventIterator* Apply(InputDatabase* self, Operation* operation); + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "InputDatabase_destroy", ExactSpelling = true)] public static unsafe extern void Destroy(InputDatabase* self); } diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputFfiResultBoxCharBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputFfiResultBoxCharBoxIronRdpError.cs new file mode 100644 index 000000000..1e721b374 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawInputFfiResultBoxCharBoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct InputFfiResultBoxCharBoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal Char* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe Char* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawMouseButton.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawMouseButton.cs new file mode 100644 index 000000000..bc7dbb033 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawMouseButton.cs @@ -0,0 +1,30 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct MouseButton +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MouseButton_new", ExactSpelling = true)] + public static unsafe extern MouseButton* New(MouseButtonType button); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MouseButton_as_operation_mouse_button_pressed", ExactSpelling = true)] + public static unsafe extern Operation* AsOperationMouseButtonPressed(MouseButton* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MouseButton_as_operation_mouse_button_released", ExactSpelling = true)] + public static unsafe extern Operation* AsOperationMouseButtonReleased(MouseButton* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MouseButton_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(MouseButton* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawMouseButtonType.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawMouseButtonType.cs new file mode 100644 index 000000000..ae7994ebe --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawMouseButtonType.cs @@ -0,0 +1,21 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +public enum MouseButtonType +{ + Left = 0, + Middle = 1, + Right = 2, + X1 = 3, + X2 = 4, +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawMousePosition.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawMousePosition.cs new file mode 100644 index 000000000..dcd70e332 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawMousePosition.cs @@ -0,0 +1,27 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct MousePosition +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MousePosition_new", ExactSpelling = true)] + public static unsafe extern MousePosition* New(ushort x, ushort y); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MousePosition_as_move_operation", ExactSpelling = true)] + public static unsafe extern Operation* AsMoveOperation(MousePosition* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MousePosition_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(MousePosition* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawOperation.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawOperation.cs new file mode 100644 index 000000000..5bd5f7621 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawOperation.cs @@ -0,0 +1,21 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct Operation +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Operation_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(Operation* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawOperationType.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawOperationType.cs new file mode 100644 index 000000000..01ab36490 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawOperationType.cs @@ -0,0 +1,24 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +public enum OperationType +{ + MouseButtonPressed = 0, + MouseButtonReleased = 1, + MouseMove = 2, + WheelRotations = 3, + KeyPressed = 4, + KeyReleased = 5, + UnicodeKeyPressed = 6, + UnicodeKeyReleased = 7, +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawScancode.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawScancode.cs new file mode 100644 index 000000000..36b28edd7 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawScancode.cs @@ -0,0 +1,33 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct Scancode +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Scancode_from_u8", ExactSpelling = true)] + public static unsafe extern Scancode* FromU8([MarshalAs(UnmanagedType.U1)] bool extended, byte code); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Scancode_from_u16", ExactSpelling = true)] + public static unsafe extern Scancode* FromU16(ushort code); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Scancode_as_operation_key_pressed", ExactSpelling = true)] + public static unsafe extern Operation* AsOperationKeyPressed(Scancode* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Scancode_as_operation_key_released", ExactSpelling = true)] + public static unsafe extern Operation* AsOperationKeyReleased(Scancode* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Scancode_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(Scancode* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawWheelRotations.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawWheelRotations.cs new file mode 100644 index 000000000..95185c5f8 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawWheelRotations.cs @@ -0,0 +1,27 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct WheelRotations +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "WheelRotations_new", ExactSpelling = true)] + public static unsafe extern WheelRotations* New([MarshalAs(UnmanagedType.U1)] bool isVertical, short rotationUnits); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "WheelRotations_as_operation", ExactSpelling = true)] + public static unsafe extern Operation* AsOperation(WheelRotations* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "WheelRotations_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(WheelRotations* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/Scancode.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/Scancode.cs new file mode 100644 index 000000000..dbc7504f9 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/Scancode.cs @@ -0,0 +1,119 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class Scancode: IDisposable +{ + private unsafe Raw.Scancode* _inner; + + /// + /// Creates a managed Scancode from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe Scancode(Raw.Scancode* handle) + { + _inner = handle; + } + + /// + /// A Scancode allocated on Rust side. + /// + public static Scancode FromU8(bool extended, byte code) + { + unsafe + { + Raw.Scancode* retVal = Raw.Scancode.FromU8(extended, code); + return new Scancode(retVal); + } + } + + /// + /// A Scancode allocated on Rust side. + /// + public static Scancode FromU16(ushort code) + { + unsafe + { + Raw.Scancode* retVal = Raw.Scancode.FromU16(code); + return new Scancode(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperationKeyPressed() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("Scancode"); + } + Raw.Operation* retVal = Raw.Scancode.AsOperationKeyPressed(_inner); + return new Operation(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperationKeyReleased() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("Scancode"); + } + Raw.Operation* retVal = Raw.Scancode.AsOperationKeyReleased(_inner); + return new Operation(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.Scancode* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.Scancode.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~Scancode() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/WheelRotations.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/WheelRotations.cs new file mode 100644 index 000000000..97077dd59 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/WheelRotations.cs @@ -0,0 +1,91 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class WheelRotations: IDisposable +{ + private unsafe Raw.WheelRotations* _inner; + + /// + /// Creates a managed WheelRotations from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe WheelRotations(Raw.WheelRotations* handle) + { + _inner = handle; + } + + /// + /// A WheelRotations allocated on Rust side. + /// + public static WheelRotations New(bool isVertical, short rotationUnits) + { + unsafe + { + Raw.WheelRotations* retVal = Raw.WheelRotations.New(isVertical, rotationUnits); + return new WheelRotations(retVal); + } + } + + /// + /// A Operation allocated on Rust side. + /// + public Operation AsOperation() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("WheelRotations"); + } + Raw.Operation* retVal = Raw.WheelRotations.AsOperation(_inner); + return new Operation(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.WheelRotations* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.WheelRotations.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~WheelRotations() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs b/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs index 38d2f8f71..3581e84d4 100644 --- a/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs +++ b/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs @@ -73,7 +73,7 @@ private static async Task ConnectFinalize(string servername, C ClientConnectorState state = connector.ConsumeAndCastToClientConnectorState(); - if (state.GetType() == ClientConnectorStateType.Connected) + if (state.GetEnumType() == ClientConnectorStateType.Connected) { return state.GetConnectedResult(); } diff --git a/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs b/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs index 56a336adb..d284790d8 100644 --- a/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs +++ b/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs @@ -6,6 +6,7 @@ public class Framed where S : Stream { private S stream; private List buffer; + private readonly Mutex writeLock = new Mutex(); public Framed(S stream) { @@ -20,7 +21,6 @@ public Framed(S stream) public async Task<(Devolutions.IronRdp.Action, byte[])> ReadPdu() { - while (true) { var pduInfo = IronRdpPdu.New().FindSize(this.buffer.ToArray()); @@ -33,7 +33,6 @@ public Framed(S stream) else { var len = await this.Read(); - if (len == 0) { throw new IronRdpLibException(IronRdpLibExceptionType.EndOfFile, "EOF on ReadPdu"); @@ -78,7 +77,7 @@ public async Task ReadExact(nuint size) async Task Read() { - var buffer = new byte[1024]; + var buffer = new byte[8096]; Memory memory = buffer; var size = await this.stream.ReadAsync(memory); this.buffer.AddRange(buffer.Take(size)); @@ -87,8 +86,20 @@ async Task Read() public async Task Write(byte[] data) { - ReadOnlyMemory memory = data; - await this.stream.WriteAsync(memory); + writeLock.WaitOne(); + try + { + ReadOnlyMemory memory = data; + await this.stream.WriteAsync(memory); + } + catch (Exception e) + { + throw e; + } + finally + { + writeLock.ReleaseMutex(); + } } diff --git a/ffi/src/connector/config.rs b/ffi/src/connector/config.rs index d150cdfea..c3804b279 100644 --- a/ffi/src/connector/config.rs +++ b/ffi/src/connector/config.rs @@ -4,10 +4,7 @@ use self::ffi::PerformanceFlagsType; #[diplomat::bridge] pub mod ffi { - use ironrdp::{ - connector::{BitmapConfig, Credentials}, - pdu::rdp::capability_sets::MajorPlatformType, - }; + use ironrdp::{connector::Credentials, pdu::rdp::capability_sets::MajorPlatformType}; use crate::error::ffi::IronRdpError; @@ -33,7 +30,7 @@ pub mod ffi { pub ime_file_name: Option, pub dig_product_id: Option, pub desktop_size: Option, - pub bitmap: Option, + pub bitmap: Option, pub client_build: Option, pub client_name: Option, pub client_dir: Option, @@ -120,7 +117,9 @@ pub mod ffi { self.performance_flags = Some(performance_flags.0); } - // TODO: set bitmap + pub fn set_bitmap_config(&mut self, bitmap: &BitmapConfig) { + self.bitmap = Some(bitmap.0); + } pub fn set_client_build(&mut self, client_build: u32) { self.client_build = Some(client_build); @@ -227,6 +226,9 @@ pub mod ffi { self.0.insert(flag.into()); } } + + #[diplomat::opaque] + pub struct BitmapConfig(pub ironrdp::connector::BitmapConfig); } impl From for PerformanceFlags { diff --git a/ffi/src/connector/state.rs b/ffi/src/connector/state.rs index 2a9519ae2..78f59b094 100644 --- a/ffi/src/connector/state.rs +++ b/ffi/src/connector/state.rs @@ -27,7 +27,7 @@ pub mod ffi { } impl ClientConnectorState { - pub fn get_type(&self) -> Result> { + pub fn get_enum_type(&self) -> Result> { let res = match &self .0 .as_ref() @@ -166,8 +166,6 @@ pub mod ffi { .map(Box::new) } - // TODO: Add more getters for other states - pub fn get_connected_result( &mut self, ) -> Result, Box> { @@ -184,5 +182,23 @@ pub mod ffi { .into()), } } + + pub fn get_connection_finalization_result( + &mut self, + ) -> Result, Box> { + match self + .0 + .take() + .ok_or_else(|| ValueConsumedError::for_item("ClientConnectorState"))? + { + ironrdp::connector::ClientConnectorState::ConnectionFinalization { connection_activation } => Ok( + crate::connector::ffi::ConnectionActivationSequence(Box::new(connection_activation)), + ), + _ => Err(IncorrectEnumTypeError::on_variant("ConnectionFinalization") + .of_enum("ClientConnectorState") + .into()), + } + .map(Box::new) + } } } diff --git a/ffi/src/input.rs b/ffi/src/input.rs index ca7eba7aa..fcdd61684 100644 --- a/ffi/src/input.rs +++ b/ffi/src/input.rs @@ -1,5 +1,7 @@ #[diplomat::bridge] pub mod ffi { + use crate::{error::ffi::IronRdpError, pdu::ffi::FastPathInputEventIterator}; + #[diplomat::opaque] pub struct InputDatabase(pub ironrdp::input::Database); @@ -7,5 +9,125 @@ pub mod ffi { pub fn new() -> Box { Box::new(InputDatabase(ironrdp::input::Database::new())) } + + pub fn apply(&mut self, operation: &Operation) -> Box { + let res = self.0.apply(std::iter::once(operation.0.clone())); + Box::new(res.to_vec().into()) + } + } + + #[diplomat::opaque] + pub struct Operation(pub ironrdp::input::Operation); + + pub enum OperationType { + MouseButtonPressed, + MouseButtonReleased, + MouseMove, + WheelRotations, + KeyPressed, + KeyReleased, + UnicodeKeyPressed, + UnicodeKeyReleased, + } + + #[diplomat::opaque] + pub struct MousePosition(pub ironrdp::input::MousePosition); + + impl MousePosition { + pub fn new(x: u16, y: u16) -> Box { + Box::new(MousePosition(ironrdp::input::MousePosition { x, y })) + } + + pub fn as_move_operation(&self) -> Box { + Box::new(Operation(ironrdp::input::Operation::MouseMove(self.0))) + } + } + + #[diplomat::opaque] + pub struct MouseButton(pub ironrdp::input::MouseButton); + + #[diplomat::enum_convert(ironrdp::input::MouseButton)] + pub enum MouseButtonType { + Left = 0, + Middle = 1, + Right = 2, + X1 = 3, + X2 = 4, + } + + impl MouseButton { + pub fn new(button: MouseButtonType) -> Box { + Box::new(MouseButton(button.into())) + } + + pub fn as_operation_mouse_button_pressed(&self) -> Box { + let operation = ironrdp::input::Operation::MouseButtonPressed(self.0); + Box::new(Operation(operation)) + } + + pub fn as_operation_mouse_button_released(&self) -> Box { + let operation = ironrdp::input::Operation::MouseButtonReleased(self.0); + Box::new(Operation(operation)) + } + } + + #[diplomat::opaque] + pub struct WheelRotations(pub ironrdp::input::WheelRotations); + + impl WheelRotations { + pub fn new(is_vertical: bool, rotation_units: i16) -> Box { + Box::new(WheelRotations(ironrdp::input::WheelRotations { + is_vertical, + rotation_units, + })) + } + + pub fn as_operation(&self) -> Box { + Box::new(Operation(ironrdp::input::Operation::WheelRotations(self.0))) + } + } + + #[diplomat::opaque] + pub struct Scancode(pub ironrdp::input::Scancode); + + impl Scancode { + pub fn from_u8(extended: bool, code: u8) -> Box { + Box::new(Scancode(ironrdp::input::Scancode::from_u8(extended, code))) + } + + pub fn from_u16(code: u16) -> Box { + Box::new(Scancode(ironrdp::input::Scancode::from_u16(code))) + } + + pub fn as_operation_key_pressed(&self) -> Box { + let operation = ironrdp::input::Operation::KeyPressed(self.0); + Box::new(Operation(operation)) + } + + pub fn as_operation_key_released(&self) -> Box { + let operation = ironrdp::input::Operation::KeyReleased(self.0); + Box::new(Operation(operation)) + } + } + + #[diplomat::opaque] + pub struct Char(pub char); + + impl Char { + pub fn new(c: u32) -> Result, Box> { + char::from_u32(c) + .map(|c| Box::new(Char(c))) + .ok_or_else(|| "Invalid unicode character".into()) + } + + pub fn as_operation_unicode_key_pressed(&self) -> Box { + let operation = ironrdp::input::Operation::UnicodeKeyPressed(self.0); + Box::new(Operation(operation)) + } + + pub fn as_operation_unicode_key_released(&self) -> Box { + let operation = ironrdp::input::Operation::UnicodeKeyReleased(self.0); + Box::new(Operation(operation)) + } } } diff --git a/ffi/src/pdu.rs b/ffi/src/pdu.rs index 57bb11555..ac53df778 100644 --- a/ffi/src/pdu.rs +++ b/ffi/src/pdu.rs @@ -58,4 +58,16 @@ pub mod ffi { Ok(ironrdp::pdu::find_size(bytes)?.map(PduInfo).map(Box::new)) } } + + #[diplomat::opaque] + pub struct FastPathInputEvent(pub ironrdp::pdu::input::fast_path::FastPathInputEvent); + + #[diplomat::opaque] + pub struct FastPathInputEventIterator(pub Vec); +} + +impl From> for ffi::FastPathInputEventIterator { + fn from(value: Vec) -> Self { + ffi::FastPathInputEventIterator(value) + } } diff --git a/ffi/src/session/mod.rs b/ffi/src/session/mod.rs index 1ba65faae..f4aca56a2 100644 --- a/ffi/src/session/mod.rs +++ b/ffi/src/session/mod.rs @@ -7,7 +7,7 @@ pub mod ffi { connector::{ffi::ConnectionActivationSequence, result::ffi::ConnectionResult}, error::{ffi::IronRdpError, IncorrectEnumTypeError, ValueConsumedError}, graphics::ffi::DecodedPointer, - pdu::ffi::{Action, InclusiveRectangle}, + pdu::ffi::{Action, FastPathInputEventIterator, InclusiveRectangle}, utils::ffi::{BytesSlice, Position}, }; @@ -55,6 +55,17 @@ pub mod ffi { let outputs = self.0.process(&mut image.0, action.0, payload)?; Ok(Box::new(ActiveStageOutputIterator(outputs))) } + + pub fn process_fastpath_input( + &mut self, + image: &mut DecodedImage, + fastpath_input: &FastPathInputEventIterator, + ) -> Result, Box> { + Ok(self + .0 + .process_fastpath_input(&mut image.0, &fastpath_input.0) + .map(|outputs| Box::new(ActiveStageOutputIterator(outputs)))?) + } } pub enum ActiveStageOutputType { @@ -69,7 +80,7 @@ pub mod ffi { } impl ActiveStageOutput { - pub fn get_type(&self) -> ActiveStageOutputType { + pub fn get_enum_type(&self) -> ActiveStageOutputType { match &self.0 { ironrdp::session::ActiveStageOutput::ResponseFrame { .. } => ActiveStageOutputType::ResponseFrame, ironrdp::session::ActiveStageOutput::GraphicsUpdate { .. } => ActiveStageOutputType::GraphicsUpdate,