diff --git a/Server/Controls/PictureBoxEx.Designer.cs b/Server/Controls/PictureBoxEx.Designer.cs
index 87e5bf7c..bc884415 100644
--- a/Server/Controls/PictureBoxEx.Designer.cs
+++ b/Server/Controls/PictureBoxEx.Designer.cs
@@ -16,7 +16,11 @@ protected override void Dispose(bool disposing)
if (disposing && (components != null))
{
components.Dispose();
+
+ // Stop running.
+ this.Stop();
}
+
base.Dispose(disposing);
}
diff --git a/Server/Controls/PictureBoxEx.cs b/Server/Controls/PictureBoxEx.cs
index 52e50e93..09bfcecc 100644
--- a/Server/Controls/PictureBoxEx.cs
+++ b/Server/Controls/PictureBoxEx.cs
@@ -1,21 +1,129 @@
using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
+using System.Diagnostics;
using System.Drawing;
-using System.Linq;
-using System.Text;
using System.Windows.Forms;
+using xServer.Core.Utilities;
namespace xServer.Controls
{
- public partial class PictureBoxEx : PictureBox
+ public delegate void PictureSizeChangedEventHandler(int width, int height);
+
+ public class PictureSizeChangedEventArgs : EventArgs
{
+ public int NewWidth;
+ public int NewHeight;
+
+ public PictureSizeChangedEventArgs(int width, int height)
+ {
+ NewWidth = width;
+ NewHeight = height;
+ }
+ }
+
+ public interface IRapidPictureBox
+ {
+ bool Running { get; set; }
+
+ void Start();
+ void Stop();
+ void UpdateImage(Bitmap bmp, bool cloneBitmap = false);
+
+ Image _Image { get; set; }
+ }
+
+ ///
+ /// Custom PictureBox Control designed for rapidly-changing images.
+ ///
+ public partial class PictureBoxEx : PictureBox, IRapidPictureBox
+ {
+ #region IRapidPictureBox Implementation
+
+ public bool Running { get; set; }
+
+ public void Start()
+ {
+ _frameCounter = new FrameCounter();
+
+ _sWatch = Stopwatch.StartNew();
+
+ Running = true;
+ }
+
+ public void Stop()
+ {
+ if (_sWatch != null)
+ _sWatch.Stop();
+
+ Running = false;
+ }
+
+ public void UpdateImage(Bitmap bmp, bool cloneBitmap = false)
+ {
+ try
+ {
+ CountFps();
+
+ if ((bmpWidth != bmp.Width) && (bmpHeight != bmp.Height))
+ OnPictureSizeChanged(new PictureSizeChangedEventArgs(bmp.Width, bmp.Height));
+
+ lock (ImgLocker)
+ {
+ if (this._Image != null)
+ {
+ this._Image.Dispose();
+ this._Image = null;
+ }
+
+ this._Image = cloneBitmap ? new Bitmap(bmp, picDesktop.Width, picDesktop.Height) /*resize bitmap*/ : bmp;
+ }
+ }
+ catch (InvalidOperationException)
+ {
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(
+ string.Format(
+ "An unexpected error occurred: {0}\n\nPlease report this as fast as possible here:\\https://github.com/MaxXor/xRAT/issues",
+ ex.Message), "", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ #endregion
+
+ // Fields used to keep track of the remote desktop's size.
+ public int bmpWidth { get; private set; }
+ public int bmpHeight { get; private set; }
+
+ // Fields for the FrameCounter.
+ public FrameCounter _frameCounter;
+ private Stopwatch _sWatch;
+
public PictureBoxEx()
{
InitializeComponent();
+
+ //this.DoubleBuffered = true;
+ this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
+
+ _frameCounter = new FrameCounter();
}
-
+
+ #region Events
+
+ public event PictureSizeChangedEventHandler PictureSizeChanged;
+
+ protected virtual void OnPictureSizeChanged(PictureSizeChangedEventArgs e)
+ {
+ PictureSizeChangedEventHandler handler = PictureSizeChanged;
+ if (handler != null)
+ handler(e.NewWidth, e.NewHeight);
+ }
+
+ #endregion
+
+ #region Overrides
+
protected override CreateParams CreateParams
{
get
@@ -28,7 +136,42 @@ protected override CreateParams CreateParams
protected override void OnPaint(PaintEventArgs pe)
{
- base.OnPaint(pe);
+ lock (ImgLocker)
+ {
+ if (this._Image != null)
+ {
+ pe.Graphics.DrawImage(this._Image, this.Location);
+ }
+ }
+ }
+
+ #endregion
+
+ private void CountFps()
+ {
+ var deltaTime = (float)_sWatch.Elapsed.TotalSeconds;
+ _sWatch = Stopwatch.StartNew();
+
+ _frameCounter.Update(deltaTime);
+ }
+
+ private readonly object ImgLocker = new object();
+ ///
+ /// Provides thread-safe access to the PictureBox's image.
+ ///
+ public Image _Image
+ {
+ get
+ {
+ return picDesktop.Image;
+ }
+ set
+ {
+ lock (ImgLocker)
+ {
+ picDesktop.Image = value;
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/Server/Core/Utilities/FrameCounter.cs b/Server/Core/Utilities/FrameCounter.cs
index 541c5b45..0b13b294 100644
--- a/Server/Core/Utilities/FrameCounter.cs
+++ b/Server/Core/Utilities/FrameCounter.cs
@@ -1,22 +1,36 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
namespace xServer.Core.Utilities
{
+ public class FrameUpdatedEventArgs : EventArgs
+ {
+ public float CurrentFramesPerSecond { get; private set; }
+
+ public FrameUpdatedEventArgs(float _CurrentFramesPerSecond)
+ {
+ CurrentFramesPerSecond = _CurrentFramesPerSecond;
+ }
+ }
+
+ public delegate void FrameUpdatedEventHandler(FrameUpdatedEventArgs e);
+
public class FrameCounter
{
public long TotalFrames { get; private set; }
public float TotalSeconds { get; private set; }
public float AverageFramesPerSecond { get; private set; }
- public float CurrentFramesPerSecond { get; private set; }
public const int MAXIMUM_SAMPLES = 100;
private Queue _sampleBuffer = new Queue();
+ public event FrameUpdatedEventHandler FrameUpdated;
+
public void Update(float deltaTime)
{
- CurrentFramesPerSecond = 1.0f / deltaTime;
+ float CurrentFramesPerSecond = 1.0f / deltaTime;
_sampleBuffer.Enqueue(CurrentFramesPerSecond);
@@ -30,8 +44,17 @@ public void Update(float deltaTime)
AverageFramesPerSecond = CurrentFramesPerSecond;
}
+ OnFrameUpdated(new FrameUpdatedEventArgs(AverageFramesPerSecond));
+
TotalFrames++;
TotalSeconds += deltaTime;
}
+
+ protected virtual void OnFrameUpdated(FrameUpdatedEventArgs e)
+ {
+ FrameUpdatedEventHandler handler = FrameUpdated;
+ if (handler != null)
+ handler(e);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/Server/Forms/FrmRemoteDesktop.cs b/Server/Forms/FrmRemoteDesktop.cs
index 7bed0fb3..1afe51e0 100644
--- a/Server/Forms/FrmRemoteDesktop.cs
+++ b/Server/Forms/FrmRemoteDesktop.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
@@ -17,8 +16,7 @@ public partial class FrmRemoteDesktop : Form
private readonly Client _connectClient;
private bool _enableMouseInput;
private bool _started;
- private FrameCounter _frameCounter;
- private Stopwatch _sWatch;
+
private int _screenWidth;
private int _screenHeight;
@@ -31,18 +29,20 @@ public FrmRemoteDesktop(Client c)
_connectClient = c;
_connectClient.Value.FrmRdp = this;
InitializeComponent();
+
+ picDesktop.PictureSizeChanged += picDesktop_PictureSizeChanged;
}
private void FrmRemoteDesktop_Load(object sender, EventArgs e)
{
this.Text = WindowHelper.GetWindowTitle("Remote Desktop", _connectClient);
- panelTop.Left = (this.Width/2) - (panelTop.Width/2);
+ panelTop.Left = (this.Width / 2) - (panelTop.Width / 2);
- btnHide.Left = (panelTop.Width/2) - (btnHide.Width/2);
+ btnHide.Left = (panelTop.Width / 2) - (btnHide.Width / 2);
btnShow.Location = new Point(377, 0);
- btnShow.Left = (this.Width/2) - (btnShow.Width/2);
+ btnShow.Left = (this.Width / 2) - (btnShow.Width / 2);
if (_connectClient.Value != null)
new Core.Packets.ServerPackets.GetMonitors().Execute(_connectClient);
@@ -50,7 +50,7 @@ private void FrmRemoteDesktop_Load(object sender, EventArgs e)
public void ProcessScreens(object state)
{
- while (true)
+ while (true && picDesktop != null && !picDesktop.IsDisposed && !picDesktop.Disposing)
{
GetDesktopResponse packet;
lock (ProcessingScreensQueue)
@@ -68,21 +68,36 @@ public void ProcessScreens(object state)
}
if (_connectClient.Value.StreamCodec == null)
- _connectClient.Value.StreamCodec = new UnsafeStreamCodec(packet.Quality, packet.Monitor, packet.Resolution);
-
- if (_connectClient.Value.StreamCodec.ImageQuality != packet.Quality || _connectClient.Value.StreamCodec.Monitor != packet.Monitor
- || _connectClient.Value.StreamCodec.Resolution != packet.Resolution)
{
- if (_connectClient.Value.StreamCodec != null)
+ _connectClient.Value.StreamCodec = new UnsafeStreamCodec(packet.Quality, packet.Monitor, packet.Resolution);
+ }
+ else if (_connectClient.Value.StreamCodec.ImageQuality != packet.Quality || _connectClient.Value.StreamCodec.Monitor != packet.Monitor)
+ {
+ if (string.Compare(_connectClient.Value.StreamCodec.Resolution, packet.Resolution, StringComparison.InvariantCultureIgnoreCase) != 0)
+ {
_connectClient.Value.StreamCodec.Dispose();
+ }
_connectClient.Value.StreamCodec = new UnsafeStreamCodec(packet.Quality, packet.Monitor, packet.Resolution);
}
using (MemoryStream ms = new MemoryStream(packet.Image))
{
- if (_connectClient.Value.FrmRdp != null)
- _connectClient.Value.FrmRdp.UpdateImage(_connectClient.Value.StreamCodec.DecodeData(ms), true);
+ try
+ {
+ // Update the new image from the packet data.
+ picDesktop.UpdateImage(_connectClient.Value.StreamCodec.DecodeData(ms), true);
+
+ this.Invoke((MethodInvoker)delegate
+ {
+ if (picDesktop != null && !picDesktop.IsDisposed && picDesktop._Image != null)
+ {
+ picDesktop.Invalidate();
+ }
+ });
+ }
+ catch
+ { }
}
packet.Image = null;
@@ -93,7 +108,7 @@ public void AddMonitors(int montiors)
{
try
{
- cbMonitors.Invoke((MethodInvoker) delegate
+ cbMonitors.Invoke((MethodInvoker)delegate
{
for (int i = 0; i < montiors; i++)
cbMonitors.Items.Add(string.Format("Monitor {0}", i + 1));
@@ -112,73 +127,27 @@ public void AddMonitors(int montiors)
}
}
- private void CountFps()
+ // Update on frame change.
+ private void _frameCounter_FrameUpdated(FrameUpdatedEventArgs e)
{
- var deltaTime = (float)_sWatch.Elapsed.TotalSeconds;
- _sWatch = Stopwatch.StartNew();
-
- _frameCounter.Update(deltaTime);
-
- UpdateFps(_frameCounter.AverageFramesPerSecond);
+ this.Invoke((MethodInvoker)delegate
+ {
+ this.Text = string.Format("{0} - FPS: {1}", WindowHelper.GetWindowTitle("Remote Desktop", _connectClient), e.CurrentFramesPerSecond.ToString("0.00"));
+ });
}
- private void UpdateFps(float fps)
- {
- try
- {
- this.Invoke((MethodInvoker)delegate
- {
- this.Text = string.Format("{0} - FPS: {1}", WindowHelper.GetWindowTitle("Remote Desktop", _connectClient), fps.ToString("0.00"));
- });
- }
- catch (InvalidOperationException)
- {
- }
- }
-
- private void UpdateScreenResolution(int width, int height)
+ private void picDesktop_PictureSizeChanged(int width, int height)
{
_screenWidth = width;
_screenHeight = height;
}
- public void UpdateImage(Bitmap bmp, bool cloneBitmap = false)
- {
- try
- {
- CountFps();
- UpdateScreenResolution(bmp.Width, bmp.Height);
- picDesktop.Invoke((MethodInvoker) delegate
- {
- // get old image to dispose it correctly
- var oldImage = picDesktop.Image;
-
- picDesktop.SuspendLayout();
- picDesktop.Image = cloneBitmap ? new Bitmap(bmp, picDesktop.Width, picDesktop.Height) /*resize bitmap*/ : bmp;
- picDesktop.ResumeLayout();
-
- if (oldImage != null)
- oldImage.Dispose();
- });
- }
- catch (InvalidOperationException)
- {
- }
- catch (Exception ex)
- {
- MessageBox.Show(
- string.Format(
- "An unexpected error occurred: {0}\n\nPlease report this as fast as possible here:\\https://github.com/MaxXor/xRAT/issues",
- ex.Message), "", MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
- }
-
private void ToggleControls(bool t)
{
_started = !t;
try
{
- this.Invoke((MethodInvoker) delegate
+ this.Invoke((MethodInvoker)delegate
{
btnStart.Enabled = t;
btnStop.Enabled = !t;
@@ -194,16 +163,16 @@ private void FrmRemoteDesktop_FormClosing(object sender, FormClosingEventArgs e)
{
if (_started)
new Core.Packets.ServerPackets.GetDesktop(0, 0, RemoteDesktopAction.Stop).Execute(_connectClient);
- if (_sWatch != null)
- _sWatch.Stop();
+ if (!picDesktop.IsDisposed && !picDesktop.Disposing)
+ picDesktop.Dispose();
if (_connectClient.Value != null)
_connectClient.Value.FrmRdp = null;
}
private void FrmRemoteDesktop_Resize(object sender, EventArgs e)
{
- panelTop.Left = (this.Width/2) - (panelTop.Width/2);
- btnShow.Left = (this.Width/2) - (btnShow.Width/2);
+ panelTop.Left = (this.Width / 2) - (panelTop.Width / 2);
+ btnShow.Left = (this.Width / 2) - (btnShow.Width / 2);
}
private void btnStart_Click(object sender, EventArgs e)
@@ -215,11 +184,13 @@ private void btnStart_Click(object sender, EventArgs e)
return;
}
- _frameCounter = new FrameCounter();
- _sWatch = Stopwatch.StartNew();
-
ToggleControls(false);
+ picDesktop.Start();
+
+ // Subscribe to the new frame counter.
+ picDesktop._frameCounter.FrameUpdated += _frameCounter_FrameUpdated;
+
new Core.Packets.ServerPackets.GetDesktop(barQuality.Value, cbMonitors.SelectedIndex, RemoteDesktopAction.Start).Execute(_connectClient);
}
@@ -227,7 +198,11 @@ private void btnStop_Click(object sender, EventArgs e)
{
new Core.Packets.ServerPackets.GetDesktop(0, 0, RemoteDesktopAction.Stop).Execute(_connectClient);
ToggleControls(true);
- _sWatch.Stop();
+
+ picDesktop.Stop();
+
+ // Unsubscribe from the frame counter. It will be re-created when starting again.
+ picDesktop._frameCounter.FrameUpdated -= _frameCounter_FrameUpdated;
}
private void barQuality_Scroll(object sender, EventArgs e)