2024-04-10 00:18:31 +09:00
|
|
|
|
using SixLabors.ImageSharp;
|
|
|
|
|
|
using SixLabors.ImageSharp.PixelFormats;
|
2024-04-05 11:11:32 -04:00
|
|
|
|
|
|
|
|
|
|
namespace Devolutions.IronRdp.ConnectExample
|
|
|
|
|
|
{
|
|
|
|
|
|
class Program
|
|
|
|
|
|
{
|
|
|
|
|
|
static async Task Main(string[] args)
|
|
|
|
|
|
{
|
2024-05-03 02:44:00 -04:00
|
|
|
|
Log.InitWithEnv();
|
|
|
|
|
|
|
2024-05-03 15:29:04 -04:00
|
|
|
|
var arguments = ParseArguments(args);
|
|
|
|
|
|
|
2024-04-09 10:13:12 -04:00
|
|
|
|
if (arguments == null)
|
2024-04-05 11:11:32 -04:00
|
|
|
|
{
|
2024-04-09 10:13:12 -04:00
|
|
|
|
return;
|
2024-04-05 11:11:32 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var serverName = arguments["--serverName"];
|
|
|
|
|
|
var username = arguments["--username"];
|
|
|
|
|
|
var password = arguments["--password"];
|
|
|
|
|
|
var domain = arguments["--domain"];
|
2025-03-25 12:05:06 +09:00
|
|
|
|
|
2024-04-05 11:11:32 -04:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-03-25 12:05:06 +09:00
|
|
|
|
var (res, framed) = await Connection.Connect(buildConfig(serverName, username, password, domain, 1980, 1080), serverName, null);
|
2024-04-09 10:13:12 -04:00
|
|
|
|
var decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(), res.GetDesktopSize().GetHeight());
|
|
|
|
|
|
var activeState = ActiveStage.New(res);
|
|
|
|
|
|
var keepLooping = true;
|
|
|
|
|
|
while (keepLooping)
|
|
|
|
|
|
{
|
|
|
|
|
|
var readPduTask = framed.ReadPdu();
|
|
|
|
|
|
Action? action = null;
|
|
|
|
|
|
byte[]? payload = null;
|
2025-04-21 11:08:50 +02:00
|
|
|
|
if (readPduTask == await Task.WhenAny(readPduTask, Task.Delay(2000)))
|
2024-04-09 10:13:12 -04:00
|
|
|
|
{
|
|
|
|
|
|
var pduReadTask = await readPduTask;
|
|
|
|
|
|
action = pduReadTask.Item1;
|
|
|
|
|
|
payload = pduReadTask.Item2;
|
|
|
|
|
|
Console.WriteLine($"Action: {action}");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Timeout");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
var outputIterator = activeState.Process(decodedImage, action, payload);
|
|
|
|
|
|
|
|
|
|
|
|
while (!outputIterator.IsEmpty())
|
|
|
|
|
|
{
|
|
|
|
|
|
var output = outputIterator.Next()!; // outputIterator.Next() is not null since outputIterator.IsEmpty() is false
|
|
|
|
|
|
Console.WriteLine($"Output type: {output.GetType()}");
|
2024-04-24 10:09:34 -04:00
|
|
|
|
if (output.GetEnumType() == ActiveStageOutputType.Terminate)
|
2024-04-09 10:13:12 -04:00
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Connection terminated.");
|
|
|
|
|
|
keepLooping = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-24 10:09:34 -04:00
|
|
|
|
if (output.GetEnumType() == ActiveStageOutputType.ResponseFrame)
|
2024-04-09 10:13:12 -04:00
|
|
|
|
{
|
|
|
|
|
|
var responseFrame = output.GetResponseFrame()!;
|
|
|
|
|
|
byte[] responseFrameBytes = new byte[responseFrame.GetSize()];
|
|
|
|
|
|
responseFrame.Fill(responseFrameBytes);
|
|
|
|
|
|
await framed.Write(responseFrameBytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
saveImage(decodedImage, "output.png");
|
|
|
|
|
|
|
2024-04-05 11:11:32 -04:00
|
|
|
|
}
|
2024-04-09 10:13:12 -04:00
|
|
|
|
catch (Exception e)
|
2024-04-05 11:11:32 -04:00
|
|
|
|
{
|
2024-04-09 23:44:57 +09:00
|
|
|
|
Console.WriteLine($"An error occurred: {e.Message}\n\nStackTrace:\n{e.StackTrace}");
|
2024-04-05 11:11:32 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-09 10:13:12 -04:00
|
|
|
|
private static void saveImage(DecodedImage decodedImage, string v)
|
|
|
|
|
|
{
|
|
|
|
|
|
int width = decodedImage.GetWidth();
|
|
|
|
|
|
int height = decodedImage.GetHeight();
|
|
|
|
|
|
var data = decodedImage.GetData();
|
|
|
|
|
|
|
|
|
|
|
|
var bytes = new byte[data.GetSize()];
|
|
|
|
|
|
data.Fill(bytes);
|
2024-04-09 23:44:57 +09:00
|
|
|
|
|
2024-04-10 00:18:31 +09:00
|
|
|
|
using Image<Rgba32> image = new Image<Rgba32>(width, height);
|
|
|
|
|
|
|
|
|
|
|
|
// We’ll mutate this struct instead of creating a new one for performance reasons.
|
|
|
|
|
|
Rgba32 color = new Rgba32(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
for (int col = 0; col < width; ++col)
|
2024-04-09 10:13:12 -04:00
|
|
|
|
{
|
2024-04-10 00:18:31 +09:00
|
|
|
|
for (int row = 0; row < height; ++row)
|
|
|
|
|
|
{
|
|
|
|
|
|
var idx = (row * width + col) * 4;
|
|
|
|
|
|
|
|
|
|
|
|
color.R = bytes[idx];
|
|
|
|
|
|
color.G = bytes[idx + 1];
|
|
|
|
|
|
color.B = bytes[idx + 2];
|
|
|
|
|
|
|
|
|
|
|
|
image[col, row] = color;
|
|
|
|
|
|
}
|
2024-04-09 10:13:12 -04:00
|
|
|
|
}
|
2024-04-09 23:44:57 +09:00
|
|
|
|
|
2024-04-10 00:18:31 +09:00
|
|
|
|
// Save the image as bitmap.
|
|
|
|
|
|
image.Save("./output.bmp");
|
2024-04-09 10:13:12 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Dictionary<string, string>? ParseArguments(string[] args)
|
2024-04-05 11:11:32 -04:00
|
|
|
|
{
|
|
|
|
|
|
if (args.Length == 0 || Array.Exists(args, arg => arg == "--help"))
|
|
|
|
|
|
{
|
|
|
|
|
|
PrintHelp();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var arguments = new Dictionary<string, string>();
|
2024-04-09 10:13:12 -04:00
|
|
|
|
string? lastKey = null;
|
2024-04-05 11:11:32 -04:00
|
|
|
|
foreach (var arg in args)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (arg.StartsWith("--"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (lastKey != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"Error: Missing value for {lastKey}.");
|
|
|
|
|
|
PrintHelp();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!IsValidArgument(arg))
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"Error: Unknown argument {arg}.");
|
|
|
|
|
|
PrintHelp();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
lastKey = arg;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (lastKey == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Error: Value without a preceding flag.");
|
|
|
|
|
|
PrintHelp();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
arguments[lastKey] = arg;
|
|
|
|
|
|
lastKey = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (lastKey != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"Error: Missing value for {lastKey}.");
|
|
|
|
|
|
PrintHelp();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return arguments;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool IsValidArgument(string argument)
|
|
|
|
|
|
{
|
|
|
|
|
|
var validArguments = new List<string> { "--serverName", "--username", "--password", "--domain" };
|
|
|
|
|
|
return validArguments.Contains(argument);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void PrintHelp()
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Usage: dotnet run -- [OPTIONS]");
|
|
|
|
|
|
Console.WriteLine("Options:");
|
|
|
|
|
|
Console.WriteLine(" --serverName <serverName> The name of the server to connect to.");
|
|
|
|
|
|
Console.WriteLine(" --username <username> The username for connection.");
|
|
|
|
|
|
Console.WriteLine(" --password <password> The password for connection.");
|
|
|
|
|
|
Console.WriteLine(" --domain <domain> The domain of the server.");
|
|
|
|
|
|
Console.WriteLine(" --help Show this message and exit.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-09 10:13:12 -04:00
|
|
|
|
private static Config buildConfig(string servername, string username, string password, string domain, int width, int height)
|
2024-04-05 11:11:32 -04:00
|
|
|
|
{
|
|
|
|
|
|
ConfigBuilder configBuilder = ConfigBuilder.New();
|
|
|
|
|
|
|
2024-04-09 10:13:12 -04:00
|
|
|
|
configBuilder.WithUsernameAndPassword(username, password);
|
2024-04-05 11:11:32 -04:00
|
|
|
|
configBuilder.SetDomain(domain);
|
2024-04-09 10:13:12 -04:00
|
|
|
|
configBuilder.SetDesktopSize((ushort)height, (ushort)width);
|
2024-04-05 11:11:32 -04:00
|
|
|
|
configBuilder.SetClientName("IronRdp");
|
|
|
|
|
|
configBuilder.SetClientDir("C:\\");
|
|
|
|
|
|
configBuilder.SetPerformanceFlags(PerformanceFlags.NewDefault());
|
|
|
|
|
|
|
|
|
|
|
|
return configBuilder.Build();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2024-04-09 23:44:57 +09:00
|
|
|
|
}
|