Giter Site home page Giter Site logo

marcusw.vncclient's Introduction

VNC-Client Library for C#

GitHub Workflow Status GitHub Nuget

This project provides a very performant, fully managed C#-Library that implements the RFB protocol for easy integration of VNC-Client features into own applications. It's also cross-platform and runs every where .NET Core (or .NET 5 and so on...) runs.

-- This library is currently in alpha state, but has proven to be quite stable and is ready for daily use. A stable release will follow, as soon as it's feature-complete. --

Sample Application

Screenshot of the sample application

Source Code: AvaloniaVncClient

Main Design Goals

  • 🌟 High performance: The usage of very efficient image encoding techniques like Tight or ZRLE allows a smooth image transmission even over slower connections. The code is also written in a way that makes it very CPU-time-saving.
  • 🌟 Platform-independence: All platform-specific components are abstracted away so the core library is theoretically usable everywhere, where C# runs, too.
  • 🌟 Server compatibility: Tested with TigerVNC Server, LibVNCServer, RealVNC VNC Connect, Vino-Server and UltraVNC. This implementation follows the RFB protocol specification very carefully, so it's probably compatible with many more servers.
  • 🌟 Stability: Battle-tested and proven to be very reliable.
  • 🌟 Modular & Extensible: The very modular API design allows the easy addition of more Security, Message and Encoding Types as well as the replacement of main implementation components.
  • 🌟 No external dependencies: The core library does not use any libraries outside of the .NET SDK.

Features

  • Highly configurable and extensible structure
  • Flexible transport layer selection (TCP by default)
  • Automatic reconnects with configurable behaviour
  • Supported security types: None, VNC Authentication
  • Supported message types: SetEncodings, FramebufferUpdateRequest, FramebufferUpdate, ServerCutText, SetDesktopSize, ServerFence, ClientFence, EnableContinuousUpdates, EndOfContinuousUpdates, PointerEvent, KeyEvent, Bell
  • Supported frame encoding types: Raw, CopyRect, zLib, ZRLE, Tight
  • Supported pseudo encoding types: Fence, ContinuousUpdates, LastRect, JPEG Quality Level, JPEG Fine-Grained Quality Level, JPEG Subsampling Level, DesktopSize, ExtendedDesktopSize
  • Allows smooth image transmission or even video streaming (over sufficiently fast connections) thanks to a very efficient implementation
  • Allows changing the JPEG quality levels
  • Supports all kinds of color depths up to - theoretically - even 32bit HDR (untested, please tell me if you know a server to test this with 😀)
  • Supports continuous framebuffer updates and advanced flow control
  • Supports keyboard and pointer input with horizontal and vertical scrolling
  • Supports clipboard sharing (currently only server to client, I'm open for PRs)
  • Full support for dynamic session resizing (server-side and client-side) with all the APIs exposed for multi-monitor scenarios
  • Option for visualizing received rectangles (useful for debugging or analytic purposes)
  • The render target can be detached or replaced and any time and the client can even run in a fully headless mode without any rendering
  • Exposes many useful connection details in an observable manner (INotifyPropertyChanged)
  • Very detailed log output for debugging/analytic purposes

Most of these features are demonstrated by the included sample applications.

NuGet-Packages

Core library: MarcusW.VncClient

This is library contains the main protocol implementation and is completely platform-agnostic thanks to some abstractions using C# interfaces. It has no external dependencies.

Adapter libraries: MarcusW.VncClient.Avalonia, more may follow...

These libraries provide platform specific implementations for the mentioned interfaces and provide e.g. user controls that can just be dropped into an UI application to make use of the VNC library very easily. These libraries depend on the core VNC library as well as the corresponding UI library.

You can find the latest packages for every commit that's pushed to master on GitHub Packages.

Support me!

Developing a VNC client implementation is hell a lot of work. Months of my spare time went into this. So if you use this library in a commercial context, please consider giving something back - and of course let me know about where you used it 😀.

Usage

Creating Connections

Let's prepare some objects which you can later use to start as many new connections as you want:

// Create and populate a default logger factory for logging to Avalonia logging sinks.
var loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new AvaloniaLoggerProvider());

// Create a vnc client object. This can be used to easily start new connections.
var vncClient = new VncClient(loggerFactory);

// Create a new authentication handler to handle authentication requests from the server
var authenticationHandler = new DemoAuthenticationHandler(); // see below

The provided DemoAuthenticationHandler gets called by the protocol implementation when the server requires newly established connections to be secured with e.g. the VNC Authentication security type. In this case the server requests a password input from the authentication handler which in turn could then show an input-dialog to the user.

public class DemoAuthenticationHandler : IAuthenticationHandler
{
    /// <inhertitdoc />
    public async Task<TInput> ProvideAuthenticationInputAsync<TInput>(RfbConnection connection, ISecurityType securityType, IAuthenticationInputRequest<TInput> request)
        where TInput : class, IAuthenticationInput
    {
        if (typeof(TInput) == typeof(PasswordAuthenticationInput))
        {
            string password = "verysecure!!"; // Retrieve the password somehow

            return (TInput)Convert.ChangeType(new PasswordAuthenticationInput(password), typeof(TInput));
        }

        throw new InvalidOperationException("The authentication input request is not supported by this authentication handler.");
    }
}

Now you can use the vncClient and authenticationHandler objects to connect to a VNC server by doing the following in the code:

// Configure the connect parameters
var parameters = new ConnectParameters {
    TransportParameters = new TcpTransportParameters {
        Host = "hostname or ip address",
        Port = 5900
    },
    AuthenticationHandler = authenticationHandler
    // There are many more parameters to explore...
};

// Start a new connection and save the returned connection object
RfbConnection = await vncClient.ConnectAsync(parameters, cancellationToken).ConfigureAwait(true);

You will receive an instance of the RfbConnection class which represents the active connection, exposes properties for the connection status and has methods to interact with it.

But probably, you also want to make the connection somehow visible on your screen. There are multiple ways to achieve this, depending on the application framework you use:

Avalonia User Control

In case of the Avalonia UI framework, there is a ready-to-use user control which can be added to applications to view connections and interact with them.

Extending an Avalonia application with VNC support is very easy, just add the NuGet-Package MarcusW.VncClient.Avalonia to your project and add a <VncView />-control to your application window. This is the place where the VNC connection will be shown.

<vnc:VncView Connection="{Binding RfbConnection}" />

The connection that is shown inside this view can be specified by setting the value of the Connection-property, either in code-behind or through a view model binding. As soon as you set a VncView to show a connection object, you will see the remote session on your screen and should be able to interact with it.

This works, because the view will register itself as the RenderTarget and OutputHandler of the connection object.

Manual Integration

If you don't want to use the prebuilt VncView control or there is none available for your used application framework, you can also manually implement the required interfaces:

  • IRenderTarget: Implement this interface to give the protocol implementation a place to render its frames to. Each time the client receives a new framebuffer update, it will call the GrabFramebufferReference method and pass the framebuffer size as an argument. Your implementation should then use some APIs of your application framework to create a bitmap of the given size or re-use the previous one, if the size didn't change (very important for performance reasons!). Now return a new object that implements IFramebufferReference to tell the protocol implementation about the memory location and the format of your bitmap. The protocol implementation will access the memory of the bitmap directly and will change its contents to render the received framebuffer update. After everything is rendered, Dispose() will be called on that framebuffer reference and your IRenderTarget implementation should ensure that the contents of the bitmap are rendered to the application window. Please take a look into the corresponding implementations for Avalonia UI as an example of how things should work: RfbRenderTarget, AvaloniaFramebufferReference
  • IOutputHandler: Implement this interface to handle some other types of output from the server. For example, HandleServerClipboardUpdate will be called by the protocol implementation, when the server notified the client about a change of the server-side clipboard content. You can then call some method of your application framework to set the client-side clipboard to the same content.

After you have implemented these interfaces, you can make the connection use them by setting the RfbConnection.RenderTarget and RfbConnection.OutputHandler properties. You can also detatch the connection form your render target by setting RfbConnection.RenderTarget to null. When doing this, the client implementation will render it's frames to nowhere, which is a useful feature to keep a connection alive in the background without wasting CPU resources on rendering the received frames.

There are also two connection parameters called InitialRenderTarget and InitialOutputHandler which allow you to attach render target and output handler right from the beginning.

To send messages for keyboard or mouse input, you can call the EnqueueMessage or SendMessageAsync method on the connection object. Again, please take a look at the Avalonia-specific implementation for details on this.

TurboJPEG Requirement

For maximum performance, this VNC client supports the Tight frame encoding type. But what makes this encoding type so efficient is mainly the use of a extremely optimized JPEG decoder called "TurboJPEG" (or libjpeg-turbo). Because of this, Tight is only available, if your application or the used operating system ships with some version of this native library. If it doesn't, this encoding type will be automatically disabled and the sample application will show a warning. Your application should probably do this, too.

In future, maybe, I'll extend my CI builds to ship precompiled TurboJPEG-binaries for the most common operating systems directly in the NuGet package. Please vote on this issue if you want this. 😀

Contributing

Contributions are always welcome! Wanna fix a bug or add support for a new protocol extension? Go ahead!

But before you spend a lot of time working on a Pull Request, please create an Issue first to communicate, what you are working on, to avoid duplicated work and maybe discuss some details about the way you're implementing the fix/feature.

Here is a very great community-maintained protocol specification that I used and which is probably also useful to you: rfbproto

🎉 Happy coding! 🎉

marcusw.vncclient's People

Contributors

marcuswichelmann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

marcusw.vncclient's Issues

Ship TurboJPEG binaries with the NuGet packages

I should probably ship the native TurboJPEG binaries for the most common operating systems directly with the NuGet packages to make usage and deployment of the library for application developers easier.

Would require some CI fun, but should be possible.

Please vote, if you want this. 😄

Handling individual rects

I'm working on an application that involves sending screen data from a VNC connection over the network. As such, I'm looking for a way to handle individual screen rects sent from the VNC server. If I implement a FramebufferReference, I'm unable to see which parts of the screen were actually updated and so am forced to send the entire framebuffer for each update, or use some sort of diff algorithm against the old framebuffer, both of which are very inefficient.

.Net 6 compatibility

Hey @MarcusWichelmann,
first of all I'd like to thank you for providing a .net vnc implementation :)

I was trying to implement your vnc client into an existing .net 6 Wpf project. It works great with a stable internet connection, but as soon as there is packet loss it gets wonky. The vnc client gets unresponsive for an undefined amount of time between 10 and up to 45 seconds (which was the highest I saw). After that It throws the following exceptions one after another and crashes in the end:

System.IO.IOException: 'Unable to read data from the transport connection' at Line 142 in StreamExtensions
System.OperationCanceledException: 'The operation was canceled.' at Line 125 in RfbMessageSender
System.PlatformNotSupportedException: 'Thread abort is not supported on this platform.' at Line 131 in BackGroundThread
System.ObjectDisposedException: 'The collection has been disposed. ObjectDisposed_ObjectName_Name' at Line 193 in RfbMessageSender

In order to create artificial package loss for testing I used a little networking tool called clumsy if that matters. https://jagt.github.io/clumsy/

As the third Exception states Thread.Abort() is not supported on this platform, I guess that there is a compatibility issue with .net 6 here?
I tried your Avalonia example and it works just fine and it reconnects after a maximum of 30 seconds. Your example targets .net core 3.1 if I got that right.

Is there a way to get this running in .net 6? Or is it maybe not even an issue of .net 6 and I am just missing something here?

On top of the described issue I also can't use the RfbConnection.CloseAsync() as it never returns after the await. This also might be related to .net 6 but i am not sure. But this issue is only minor and I can work arround it but maybe you have an idea why this happens.

Kind Regards
Luis Payer

Unable to connect to libvnvserver instance

I try to connect to a vncserver instance of an libvncserver implementation (https://github.com/ponty/framebuffer-vncserver)
The connection to the server works nicely with UltraVNC Client with some information of the server log:

Initializing framebuffer device /dev/fb0...
  xres=800, yres=480, xresv=800, yresv=480, xoffs=0, yoffs=0, bpp=32
  offset:length red=16:8 green=8:8 blue=0:8 transp=24:8
No keyboard device
No touch device
Initializing VNC server:
        width:  800
        height: 480
        bpp:    32
        port:   5900
        rotate: 0
  touch rotate: 0
    target FPS: 10
Initializing server...
06/02/2022 12:13:52 Listening for VNC connections on TCP port 5900
06/02/2022 12:13:52 Listening for VNC connections on TCP6 port 5900
06/02/2022 12:14:09   other clients:
06/02/2022 12:14:09 Normal socket connection
06/02/2022 12:14:09 Client Protocol Version 3.8
06/02/2022 12:14:09 Protocol version sent 3.8, using 3.8
06/02/2022 12:14:09 rfbProcessClientSecurityType: executing handler for type 1
06/02/2022 12:14:09 rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8
06/02/2022 12:14:11 Pixel format for client 192.168.2.254:
06/02/2022 12:14:11   32 bpp, depth 32, little endian
06/02/2022 12:14:11   true colour: max r 255 g 255 b 255, shift r 0 g 8 b 16
06/02/2022 12:14:11 no translation needed
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x0000001D)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x0000001B)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x0000001A)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x00000019)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x00000013)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x00000012)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0x0000000A)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type zlibhex
06/02/2022 12:14:11 Using compression level 6 for client 192.168.2.254
06/02/2022 12:14:11 Enabling full-color cursor updates for client 192.168.2.254
06/02/2022 12:14:11 Enabling cursor position updates for client 192.168.2.254
06/02/2022 12:14:11 Using image quality level 8 for client 192.168.2.254
06/02/2022 12:14:11 Using JPEG subsampling 0, Q92 for client 192.168.2.254
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFF000B)
06/02/2022 12:14:11 Enabling LastRect protocol extension for client 192.168.2.254
06/02/2022 12:14:11 Enabling NewFBSize protocol extension for client 192.168.2.254
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFFFECC)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFF8000)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFF8001)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFF8004)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFF8002)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFF8003)
06/02/2022 12:14:11 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xC0A1E5CE)
06/02/2022 12:14:11 Using ZRLE encoding for client 192.168.2.254

Attempts to connect with this VncClient prduces this server log:

Initializing framebuffer device /dev/fb0...
  xres=800, yres=480, xresv=800, yresv=480, xoffs=0, yoffs=0, bpp=32
  offset:length red=16:8 green=8:8 blue=0:8 transp=24:8
No keyboard device
No touch device
Initializing VNC server:
        width:  800
        height: 480
        bpp:    32
        port:   5900
        rotate: 0
  touch rotate: 0
    target FPS: 10
Initializing server...
06/02/2022 12:15:53 Listening for VNC connections on TCP port 5900
06/02/2022 12:15:53 Listening for VNC connections on TCP6 port 5900
06/02/2022 12:16:31   other clients:
06/02/2022 12:16:31 Normal socket connection
06/02/2022 12:16:31 Client Protocol Version 3.8
06/02/2022 12:16:31 Protocol version sent 3.8, using 3.8
06/02/2022 12:16:31 rfbProcessClientSecurityType: executing handler for type 1
06/02/2022 12:16:31 rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8
06/02/2022 12:16:31 Using fine quality level 100 for client 192.168.2.254
06/02/2022 12:16:31 Using image quality level 9 for client 192.168.2.254
06/02/2022 12:16:31 Using JPEG subsampling 0, Q100 for client 192.168.2.254
06/02/2022 12:16:31 Enabling LastRect protocol extension for client 192.168.2.254
06/02/2022 12:16:31 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFFFEC7)
06/02/2022 12:16:31 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFFFEC8)
06/02/2022 12:16:31 Enabling NewFBSize protocol extension for client 192.168.2.254
06/02/2022 12:16:31 Using subsampling level 0 for client 192.168.2.254
06/02/2022 12:16:31 rfbProcessClientNormalMessage: ignoring unsupported encoding type Enc(0xFFFFFECC)
06/02/2022 12:16:31 Using ZRLE encoding for client 192.168.2.254

and produces an exception:

Received invalid RLE palette index of 508 for a palette of 12 bytes.
at
MarcusW.VncClient.Protocol.Implementation.EncodingTypes.Frame.ZrleEncodingType.ReadPaletteRleTile(Stream stream, Boolean hasTargetFramebuffer, FramebufferCursor& framebufferCursor, Rectangle& tile, PixelFormat& cPixelFormat, Int32 paletteSize) 
in .\MarcusW.VncClient-master\src\MarcusW.VncClient\Protocol\Implementation\EncodingTypes\Frame\ZrleEncodingType.cs: Zeile412

Any chance to get it working (happy to help to narrow down the issue)?
Can i configure the client to use another encoding implementation?

Xamarin Forms

Hello!

Very nice library!

Will this library be availble for xamarin.forms?
Just wondering since you are using .net core.

Best regards

Multi-target to .NET Standard 2.1

As pointed out in #6, .NET 5.0 is not yet available on all platforms. I'll have to check, if I could also target .NET Standard 2.1 and if all required APIs are supported there.

有一些问题需要请教

我使用net5 webapi想接入完成一套本地的网站,让用户打开之后可以在网页上展示所有连接的VNC设备的实时画面并操作,想请教一下有什么办法或思路可以实现嘛

I use the net5 webapi to access and complete a set of local websites, so that users can display the real-time images of all connected VNC devices and operate them on the website after opening. I want to ask what methods or ideas can be achieved

ConnectTimeout should also cancel the handshake/initialization procedure when the server stopped responding

When the TCP socket is open, but the server is not responding (wrong port or server process is paused/broken) the ConnectTimeout should still have an effect.
Currently, the server is waiting forever for a response.

Maybe use the builtin ReceiveTimeout and disable it as soon as the connection is initialized?

Add a separate ProtocolTimeout/HandshakeTimeout/whatever property to the connect parameters?

Connection established successfully, but no output is shown on the window

Hello! I want to use this library for an Avalonia project which I started working on these lasts days just for fun for a custom viewer for my QEMU VMs, but I cannot make it work with my projects.

I've downloaded this repo and the sample project connects perfectly to my machine (either by 127.0.0.1 or 0.0.0.0; both with ports 5901).

Captura de pantalla a 2023-05-23 00-31-58

The logs don't show anything suspicious either:

/home/xavier/RiderProjects/MarcusW.VncClient/samples/AvaloniaVncClient/bin/Debug/netcoreapp3.1/AvaloniaVncClient
info: AvaloniaVncClient.Views.MainWindow[0]
Hello World!
info: MarcusW.VncClient.RfbConnection[0]
Connecting to VNC-Server on vnc://127.0.0.1:5901...
warn: MarcusW.VncClient.Protocol.Implementation.DefaultImplementation[0]
The TurboJPEG library is not installed on the current system. Please expect a performance drop, because the Tight encoding type is not available.
info: MarcusW.VncClient.RfbConnection[0]
Connection to vnc://127.0.0.1:5901 established successfully.

But when I try to add it to my projects, nothing appears on the screen.
I've created a small project with nothing but an empty window with the VncView component in it, and I followed the README.md steps.

MainWindow.axaml:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:fakevm="using:EmptyVNC.Views"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vnc="clr-namespace:MarcusW.VncClient.Avalonia;assembly=MarcusW.VncClient.Avalonia"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="EmptyVNC.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="EmptyVNC">

    <Design.DataContext><fakevm:MainWindow/></Design.DataContext>

	<vnc:VncView Connection="{Binding RfbConnection}"/>
</Window>

MainWindow.axaml.cs:

using System;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using MarcusW.VncClient;
using MarcusW.VncClient.Avalonia.Adapters.Logging;
using MarcusW.VncClient.Protocol.Implementation.Services.Transports;
using MarcusW.VncClient.Protocol.SecurityTypes;
using MarcusW.VncClient.Security;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;

namespace EmptyVNC.Views
{
	public partial class MainWindow : Window
	{
		public object? RfbConnection { get; set; }

		public MainWindow()
		{
			InitializeComponent();
			
			Connect();
		}

		public async Task Connect()
		{
			IHost host = Host.CreateDefaultBuilder().ConfigureServices((context, services) =>
			{
				services.AddLogging(loggingBuilder =>
				{
					loggingBuilder.AddConsole();
					loggingBuilder.AddProvider(new AvaloniaLoggerProvider());
				});
			}).Build();

			ILogger<MainWindow> logger = host.Services.GetRequiredService<ILogger<MainWindow>>();
			logger.LogInformation("Hello World!");
			
			ILoggerFactory loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
			VncClient vncClient = new VncClient(loggerFactory);

			IAuthenticationHandler authenticationHandler = new DemoAuthenticationHandler();
			
			ConnectParameters parameters = new ConnectParameters
			{
				TransportParameters = new TcpTransportParameters
				{
					Host = "127.0.0.1",
					Port = 5901
				},
				AuthenticationHandler = authenticationHandler
			};
			
			CancellationToken cancellationToken = CancellationToken.None;

			RfbConnection = await vncClient.ConnectAsync(parameters, cancellationToken).ConfigureAwait(true);
		}
	}
	
	public class DemoAuthenticationHandler : IAuthenticationHandler
	{
		public Task<TInput> ProvideAuthenticationInputAsync<TInput>(RfbConnection connection, ISecurityType securityType, IAuthenticationInputRequest<TInput> request)
			where TInput : class, IAuthenticationInput
		{
			if(typeof(TInput)==typeof(PasswordAuthenticationInput))
			{
				string password = String.Empty;

				return Task.FromResult((TInput)Convert.ChangeType(new PasswordAuthenticationInput(password), typeof(TInput)));
			}

			throw new InvalidOperationException("The authentication input request is not supported by this authentication handler.");
		}
	}
}

When I compile the application, the window is empty:
Captura de pantalla a 2023-05-23 00-31-38

And in the logs, it appears that the connection gets established successfully, but there's still no output on the screen.

/home/xavier/RiderProjects/EmptyVNC/bin/Debug/net5.0/EmptyVNC
info: EmptyVNC.Views.MainWindow[0]
Hello World!
info: MarcusW.VncClient.RfbConnection[0]
Connecting to VNC-Server on vnc://127.0.0.1:5901...
warn: MarcusW.VncClient.Protocol.Implementation.DefaultImplementation[0]
The TurboJPEG library is not installed on the current system. Please expect a performance drop, because the Tight encoding type is not available.
info: MarcusW.VncClient.RfbConnection[0]
Connection to vnc://127.0.0.1:5901 established successfully.

I'm using .NET 5 and Avalonia 0.10; from my Ubuntu MATE 20.04 LTS.
I noticed that the sample project uses .NET Core 3.1, I tried to switch my projects to 3.1 but still the same: white window.

I don't understand why the sample project works, but my projects do not. I've put everything the README says.
If I had to guess, I would say that I need something of MVVM and/or ReactiveUI, but I'm still a noob in these lasts things. I tried adding doing some MVVM tests but for now the same white window appears.

I've tried other VNC clients like Remmina 1.4.2, and it connects perfectly to the machine.

What I'm I missing here?

Updating the screen

Hello,
Thank you for the libs.
I faced with problem, that VncView doesn't update all view, but update place under the mouse.
It appears on start with automatic connection and switching tabs in tabview.
Looks like I do something wrong.
Could you explain how avoid this?
image

Program exits with code 0 on connect

Hi! I'm currently trying to write a VNC demo which outputs each frame as an ImageSharp image (as discussed in #17). However upon running my program, the ConnectAsync() function causes the program to exit with code 0, no error message and nothing written to the logger.

Here's my code (bit long)

using MarcusW.VncClient;
using MarcusW.VncClient.Protocol.Implementation.Services.Transports;
using MarcusW.VncClient.Protocol.SecurityTypes;
using MarcusW.VncClient.Rendering;
using MarcusW.VncClient.Security;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using Size = MarcusW.VncClient.Size;


namespace Vnctest {
    public class VNCController {
        public string host;
        public int port;
        public CancellationToken cancellationToken = new CancellationToken();
        LoggerFactory logger = new LoggerFactory();
        VncClient client;
        ConnectParameters parameters;
        RfbConnection? rfb;
        IAuthenticationHandler authenticationHandler;
        public VNCController(string host, int port, string password = "") {
            this.host = host;
            this.port = port;
            logger.AddProvider(new VNCLoggerProvider());
            client = new VncClient(logger);
            authenticationHandler = new DemoAuthenticationHandler(password);
            parameters = new ConnectParameters {
                TransportParameters = new TcpTransportParameters {
                    Host = host,
                    Port = port
                },
                AuthenticationHandler = authenticationHandler,
                InitialRenderTarget = new VNCRenderTarget(this)
            };
        }
        public async void Connect() {
            Console.WriteLine("About to try connecting");
            rfb = await client.ConnectAsync(this.parameters, cancellationToken).ConfigureAwait(false);
            Console.WriteLine("It's alive");
        }
        public async void Disconnect() {
            if (rfb == null) {
                return;
            }
            await rfb.CloseAsync();
            rfb = null;
        }
        public async void renderFrame(byte[] rgbaArray, Size size) {
            Image<Rgba32> image = Image.LoadPixelData<Rgba32>(rgbaArray, size.Width, size.Height);
            MemoryStream frameStream = new MemoryStream();
            image.SaveAsPng(frameStream);
            byte[] pngData = frameStream.ToArray();
            Console.WriteLine(Convert.ToBase64String(pngData));
        }
    }
    public class VNCRenderTarget : IRenderTarget, IDisposable {
        bool disposed = false;
        byte[]? rgbaArray = null;
        VNCController parent;
        public VNCRenderTarget(VNCController controller) {
            this.parent = controller;
        }
        public virtual IFramebufferReference GrabFramebufferReference(Size size, IImmutableSet<Screen> layout) {
            if (disposed) {
                throw new ObjectDisposedException(nameof(VNCRenderTarget));
            }
            int pixelsNeeded = size.Height * size.Width;
            rgbaArray = new byte[pixelsNeeded];
            return new VNCFramebufferReference(rgbaArray, size, parent);
        }
        public void Dispose() {
            rgbaArray = null;
            disposed = true;
        }
    }
    public unsafe sealed class VNCFramebufferReference : IFramebufferReference {
        byte[] rgbaArray;
        Memory<byte> rgbaArrMem => rgbaArray.AsMemory();
        MemoryHandle pinHandler => rgbaArrMem.Pin();
        Size size;
        public IntPtr Address => (IntPtr)pinHandler.Pointer;
        public Size Size => size;
        public PixelFormat Format => new PixelFormat("Plain RGBA", 32, 32, bigEndian: false, trueColor: true, hasAlpha: true, 255, 255, 255, 255, 24, 16, 8, 0);
        public double HorizontalDpi => Size.Height;
        public double VerticalDpi => Size.Width;
        VNCController parentController;
        internal VNCFramebufferReference(byte[] rgbaArray, Size size, VNCController parentController) {
            this.rgbaArray = rgbaArray;
            this.size = size;
            this.parentController = parentController;
        }
        public void Dispose() {
            pinHandler.Dispose();
            parentController.renderFrame(rgbaArray, size);
        }
    }
    public class DemoAuthenticationHandler : IAuthenticationHandler {
        public string password { set; get; }
        public DemoAuthenticationHandler(string password)  {
            this.password = password;
        }
        public async Task<TInput> ProvideAuthenticationInputAsync<TInput>(RfbConnection connection, ISecurityType securityType, IAuthenticationInputRequest<TInput> request)
            where TInput : class, IAuthenticationInput {
            if (typeof(TInput) == typeof(PasswordAuthenticationInput)) {
                string password = this.password;
                return (TInput)Convert.ChangeType(new PasswordAuthenticationInput(password), typeof(TInput));
            }
            throw new InvalidOperationException("The authentication input request is not supported by this authentication handler.");
        }
    }
    public class VNCLogger : ILogger {
        private const string AreaName = "VncClient";
        private readonly string _categoryName;
        internal VNCLogger(string categoryName) {
            _categoryName = categoryName;
        }
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, [NotNull] Func<TState, Exception?, string> formatter) {
            if (formatter == null)
                throw new ArgumentNullException(nameof(formatter));
            string message = $"{_categoryName}: {formatter(state, exception)}";
            if (exception != null)
                message += Environment.NewLine + exception + Environment.NewLine;
            Console.WriteLine(message);
        }
        public bool IsEnabled(LogLevel logLevel) {
            return true; // idk
        }
        public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
        public class NullScope : IDisposable {
            public static NullScope Instance { get; } = new NullScope();
            private NullScope() { }
            public void Dispose() { }
        }
    }
    public class VNCLoggerProvider : ILoggerProvider {
        private readonly ConcurrentDictionary<string, VNCLogger> _loggers =
            new ConcurrentDictionary<string, VNCLogger>();
        public ILogger CreateLogger(string categoryName) {
            if (categoryName == null)
                throw new ArgumentNullException(nameof(categoryName));
            return _loggers.GetOrAdd(categoryName, loggerName => new VNCLogger(categoryName));
        }
        public void Dispose() { }
    }
    public class Vnctest {
        public static void Main() {
            VNCController controller = new VNCController("127.0.0.1", 5900);
            controller.Connect();
        }
    }
}

When the program is run I get the following output:

About to try connecting
MarcusW.VncClient.RfbConnection: Connecting to VNC-Server on vnc://127.0.0.1:5900...
MarcusW.VncClient.Protocol.Implementation.ProtocolState: Initializing sets for used message and encoding types...
MarcusW.VncClient.Protocol.Implementation.Services.Transports.TransportConnector: Connecting to TCP endpoint vnc://127.0.0.1:5900...

C:\Users\Elijah\source\repos\vnctest\vnctest\bin\Debug\net6.0\vnctest.exe (process 13940) exited with code 0.

I don't think it's a problem with my framebuffer reference because it exits without even connecting.

Any help would be greatly appreciated!

ImageSharp

Hi! Do you have any pointers on getting your library to work with ImageSharp? I've read through the documentation and am honestly quite confused, it'd be great if you could help a bit. My goal is to, on each frame update, render the frame into an ImageSharp image for use with my program. Thanks!

Exception Occurs When Executing CloseAsync() and Dispose() Method

Based on the API documentation available at
https://vnc-client.marcusw.de/apidoc/api/MarcusW.VncClient.RfbConnection.html#methods,
I attempted to disconnect from the server using two methods bellow, however, both methods resulted in an exception being raised:

  • RfbConnection.CloseAsync()
    image

  • RfbConnection.Dispose().
    image

with:
RfbConnection = await _connectionManager.ConnectAsync(parameters, cancellationToken).ConfigureAwait(true);
(Source:

RfbConnection = await _connectionManager.ConnectAsync(parameters, cancellationToken).ConfigureAwait(true);
)

I'm uncertain whether my implementation is incorrect or if the two methods mentioned above are not fully implemented yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.