diff --git a/Remotely_Agent/Properties/launchSettings.json b/Remotely_Agent/Properties/launchSettings.json index d1f214e8..60efa336 100644 --- a/Remotely_Agent/Properties/launchSettings.json +++ b/Remotely_Agent/Properties/launchSettings.json @@ -1,7 +1,8 @@ { "profiles": { "Agent": { - "commandName": "Project" + "commandName": "Project", + "nativeDebugging": true } } } \ No newline at end of file diff --git a/Remotely_Agent/Resources/Remotely_ScreenCast.exe b/Remotely_Agent/Resources/Remotely_ScreenCast.exe index 5f89315c..34cab607 100644 Binary files a/Remotely_Agent/Resources/Remotely_ScreenCast.exe and b/Remotely_Agent/Resources/Remotely_ScreenCast.exe differ diff --git a/Remotely_Agent/Services/DeviceSocket.cs b/Remotely_Agent/Services/DeviceSocket.cs index 71e7b603..619963af 100644 --- a/Remotely_Agent/Services/DeviceSocket.cs +++ b/Remotely_Agent/Services/DeviceSocket.cs @@ -224,25 +224,7 @@ namespace Remotely_Agent.Services { Uninstaller.UninstallClient(); }); - hubConnection.On("LaunchRCInNewDesktop", async (string[] viewerIDs, string serviceID, string desktop) => - { - if (!IsServerVerified) - { - Logger.Write("Remote control attempted before server was verified."); - Uninstaller.UninstallClient(); - return; - } - var rcBinaryPath = Path.Combine(Utilities.AppDataDir, "remote_control", OSUtils.ScreenCastExecutableFileName); - var procInfo = new ADVAPI32.PROCESS_INFORMATION(); - var processResult = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode desktopswitch -viewers {String.Join(",",viewerIDs)} -serviceid {serviceID} -desktop {desktop} -hostname {Utilities.GetConnectionInfo().Host.Split("//").Last()}", desktop, true, out procInfo); - if (!processResult) - { - foreach (var viewer in viewerIDs) - { - await hubConnection.InvokeAsync("DesktopSwitchFailed", viewer); - } - } - }); + hubConnection.On("RemoteControl", async (string requesterID, string serviceID) => { if (!IsServerVerified) diff --git a/Remotely_ScreenCast/Capture/BitBltCapture.cs b/Remotely_ScreenCast/Capture/BitBltCapture.cs index 5880232e..b1573b66 100644 --- a/Remotely_ScreenCast/Capture/BitBltCapture.cs +++ b/Remotely_ScreenCast/Capture/BitBltCapture.cs @@ -26,6 +26,7 @@ namespace Remotely_ScreenCast.Capture public int PauseForMilliseconds { get; set; } public EventHandler ScreenChanged { get; set; } private Stopwatch FramerateTimer { get; } = Stopwatch.StartNew(); + private object ScreenLock { get; } = new object(); public int SelectedScreen { get @@ -38,16 +39,21 @@ namespace Remotely_ScreenCast.Capture { return; } - if (Screen.AllScreens.Length >= value + 1) + lock (ScreenLock) { - selectedScreen = value; + if (Screen.AllScreens.Length >= value + 1) + { + selectedScreen = value; + } + else + { + selectedScreen = 0; + } + CurrentScreenBounds = Screen.AllScreens[selectedScreen].Bounds; + CaptureFullscreen = true; + Init(); + ScreenChanged?.Invoke(this, CurrentScreenBounds); } - else - { - selectedScreen = 0; - } - CurrentScreenBounds = Screen.AllScreens[selectedScreen].Bounds; - ScreenChanged?.Invoke(this, CurrentScreenBounds); } } public Rectangle CurrentScreenBounds { get; set; } = Screen.PrimaryScreen.Bounds; @@ -57,11 +63,16 @@ namespace Remotely_ScreenCast.Capture public BitBltCapture() + { + Init(); + } + + private void Init() { CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb); PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb); graphic = Graphics.FromImage(CurrentFrame); - desktopName = Win32Interop.GetCurrentDesktop(); + desktopName = Win32Interop.GetCurrentDesktop(); } public void Capture() @@ -87,7 +98,10 @@ namespace Remotely_ScreenCast.Capture try { - graphic.CopyFromScreen(0 + CurrentScreenBounds.Left, 0 + CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height)); + lock (ScreenLock) + { + graphic.CopyFromScreen(0 + CurrentScreenBounds.Left, 0 + CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height)); + } } catch (Exception ex) { diff --git a/Remotely_ScreenCast/Capture/DXCapture.cs b/Remotely_ScreenCast/Capture/DXCapture.cs index cb09f60f..c9ef8dd5 100644 --- a/Remotely_ScreenCast/Capture/DXCapture.cs +++ b/Remotely_ScreenCast/Capture/DXCapture.cs @@ -2,17 +2,12 @@ using SharpDX; using SharpDX.Direct3D11; using SharpDX.DXGI; -using SharpDX.Mathematics.Interop; using System; -using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; -using System.IO; using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; using Win32; namespace Remotely_ScreenCast.Capture @@ -52,96 +47,107 @@ namespace Remotely_ScreenCast.Capture selectedScreen = 0; } } + CaptureFullscreen = true; NeedsInit = true; } } public bool NeedsInit { get; set; } = true; private string desktopName; - private Factory1 factory; - private Adapter1 adapter; - private SharpDX.Direct3D11.Device device; - private Output output; - private Output1 output1; - private int width; - private int height; - private Texture2DDescription textureDesc; - private Texture2D screenTexture; - private OutputDuplication duplicatedOutput; + private Factory1 factory; + private Adapter1 adapter; + private SharpDX.Direct3D11.Device device; + private Output output; + private Output1 output1; + private int width; + private int height; + private Texture2DDescription textureDesc; + private Texture2D screenTexture; + private OutputDuplication duplicatedOutput; private int selectedScreen = 0; + private object ScreenLock { get; } = new object(); private void Init() - { - desktopName = Win32Interop.GetCurrentDesktop(); - - factory = new Factory1(); - - //Get first adapter - adapter = factory.Adapters1.FirstOrDefault(x => x.Outputs.Length > 0); - //Get device from adapter - device = new SharpDX.Direct3D11.Device(adapter); - //Get front buffer of the adapter - if (adapter.GetOutputCount() < selectedScreen + 1) + { + try { - selectedScreen = 0; - } - output = adapter.GetOutput(selectedScreen); - output1 = output.QueryInterface(); + lock (ScreenLock) + { + desktopName = Win32Interop.GetCurrentDesktop(); + factory = new Factory1(); - // Width/Height of desktop to capture - var bounds = output.Description.DesktopBounds; - var newWidth = bounds.Right - bounds.Left; - var newHeight = bounds.Bottom - bounds.Top; - CurrentScreenBounds = new Rectangle(bounds.Left, bounds.Top, newWidth, newHeight); - if (newWidth != width || newHeight != height) + //Get first adapter + adapter = factory.Adapters1.FirstOrDefault(x => x.Outputs.Length > 0); + //Get device from adapter + device = new SharpDX.Direct3D11.Device(adapter); + //Get front buffer of the adapter + if (adapter.GetOutputCount() < selectedScreen + 1) + { + selectedScreen = 0; + } + output = adapter.GetOutput(selectedScreen); + output1 = output.QueryInterface(); + + // Width/Height of desktop to capture + var bounds = output.Description.DesktopBounds; + var newWidth = bounds.Right - bounds.Left; + var newHeight = bounds.Bottom - bounds.Top; + CurrentScreenBounds = new Rectangle(bounds.Left, bounds.Top, newWidth, newHeight); + if (newWidth != width || newHeight != height) + { + ScreenChanged?.Invoke(this, CurrentScreenBounds); + } + width = newWidth; + height = newHeight; + + CurrentFrame = new Bitmap(width, height); + PreviousFrame = new Bitmap(width, height); + + // Create Staging texture CPU-accessible + textureDesc = new Texture2DDescription + { + CpuAccessFlags = CpuAccessFlags.Read, + BindFlags = BindFlags.None, + Format = Format.B8G8R8A8_UNorm, + Width = width, + Height = height, + OptionFlags = ResourceOptionFlags.None, + MipLevels = 1, + ArraySize = 1, + SampleDescription = { Count = 1, Quality = 0 }, + Usage = ResourceUsage.Staging + }; + screenTexture = new Texture2D(device, textureDesc); + duplicatedOutput = output1.DuplicateOutput(device); + } + } + catch (Exception ex) { - ScreenChanged?.Invoke(this, CurrentScreenBounds); + Logger.Write(ex); } - width = newWidth; - height = newHeight; - - CurrentFrame = new Bitmap(width, height); - PreviousFrame = new Bitmap(width, height); - - // Create Staging texture CPU-accessible - textureDesc = new Texture2DDescription - { - CpuAccessFlags = CpuAccessFlags.Read, - BindFlags = BindFlags.None, - Format = Format.B8G8R8A8_UNorm, - Width = width, - Height = height, - OptionFlags = ResourceOptionFlags.None, - MipLevels = 1, - ArraySize = 1, - SampleDescription = { Count = 1, Quality = 0 }, - Usage = ResourceUsage.Staging - }; - screenTexture = new Texture2D(device, textureDesc); - duplicatedOutput = output1.DuplicateOutput(device); } - public void Capture() - { - try - { + public void Capture() + { + try + { if (NeedsInit) { Init(); NeedsInit = false; } - var currentDesktop = Win32Interop.GetCurrentDesktop(); - if (currentDesktop != desktopName) - { - desktopName = currentDesktop; - var inputDesktop = Win32Interop.OpenInputDesktop(); - var success = User32.SetThreadDesktop(inputDesktop); - User32.CloseDesktop(inputDesktop); - Logger.Write($"Set thread desktop to {currentDesktop}: {success}"); + var currentDesktop = Win32Interop.GetCurrentDesktop(); + if (currentDesktop != desktopName) + { + desktopName = currentDesktop; + var inputDesktop = Win32Interop.OpenInputDesktop(); + var success = User32.SetThreadDesktop(inputDesktop); + User32.CloseDesktop(inputDesktop); + Logger.Write($"Set thread desktop to {currentDesktop}: {success}"); return; - } + } - SharpDX.DXGI.Resource screenResource; - OutputDuplicateFrameInformation duplicateFrameInformation; + SharpDX.DXGI.Resource screenResource; + OutputDuplicateFrameInformation duplicateFrameInformation; // Keep framerate below 30 FPS. if (FramerateTimer.Elapsed.TotalMilliseconds > 33) @@ -150,67 +156,70 @@ namespace Remotely_ScreenCast.Capture } FramerateTimer.Restart(); - // Try to get duplicated frame within given time is ms - duplicatedOutput.AcquireNextFrame(50, out duplicateFrameInformation, out screenResource); + lock (ScreenLock) + { + // Try to get duplicated frame within given time is ms + duplicatedOutput.AcquireNextFrame(50, out duplicateFrameInformation, out screenResource); - while (duplicateFrameInformation.AccumulatedFrames < 1) - { - duplicatedOutput.ReleaseFrame(); - duplicatedOutput.AcquireNextFrame(50, out duplicateFrameInformation, out screenResource); - } + while (duplicateFrameInformation.AccumulatedFrames < 1) + { + duplicatedOutput.ReleaseFrame(); + duplicatedOutput.AcquireNextFrame(50, out duplicateFrameInformation, out screenResource); + } - // copy resource into memory that can be accessed by the CPU - using (var screenTexture2D = screenResource.QueryInterface()) - device.ImmediateContext.CopyResource(screenTexture2D, screenTexture); + // copy resource into memory that can be accessed by the CPU + using (var screenTexture2D = screenResource.QueryInterface()) + device.ImmediateContext.CopyResource(screenTexture2D, screenTexture); - // Get the desktop capture texture - var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None); + // Get the desktop capture texture + var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None); - // Create Drawing.Bitmap - using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb)) - { - var boundsRect = new Rectangle(0, 0, width, height); + // Create Drawing.Bitmap + using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb)) + { + var boundsRect = new Rectangle(0, 0, width, height); - // Copy pixels from screen capture Texture to GDI bitmap - var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat); - var sourcePtr = mapSource.DataPointer; - var destPtr = mapDest.Scan0; - for (int y = 0; y < height; y++) - { - // Copy a single line - SharpDX.Utilities.CopyMemory(destPtr, sourcePtr, width * 4); + // Copy pixels from screen capture Texture to GDI bitmap + var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat); + var sourcePtr = mapSource.DataPointer; + var destPtr = mapDest.Scan0; + for (int y = 0; y < height; y++) + { + // Copy a single line + SharpDX.Utilities.CopyMemory(destPtr, sourcePtr, width * 4); - // Advance pointers - sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch); - destPtr = IntPtr.Add(destPtr, mapDest.Stride); - } + // Advance pointers + sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch); + destPtr = IntPtr.Add(destPtr, mapDest.Stride); + } - // Release source and dest locks - bitmap.UnlockBits(mapDest); - device.ImmediateContext.UnmapSubresource(screenTexture, 0); + // Release source and dest locks + bitmap.UnlockBits(mapDest); + device.ImmediateContext.UnmapSubresource(screenTexture, 0); - PreviousFrame = (Bitmap)CurrentFrame.Clone(); - CurrentFrame = (Bitmap)bitmap.Clone(); + PreviousFrame = (Bitmap)CurrentFrame.Clone(); + CurrentFrame = (Bitmap)bitmap.Clone(); - screenResource.Dispose(); - duplicatedOutput.ReleaseFrame(); - } - } - catch (SharpDXException e) - { - if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) - { + screenResource.Dispose(); + duplicatedOutput.ReleaseFrame(); + } + } + } + catch (SharpDXException e) + { + if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) + { Logger.Write(e); - Init(); - Capture(); - } - } - catch (Exception e) - { + Init(); + Capture(); + } + } + catch (Exception e) + { Logger.Write(e); - Init(); - Capture(); - } - } + Init(); + Capture(); + } + } } } diff --git a/Remotely_ScreenCast/Capture/ScreenCaster.cs b/Remotely_ScreenCast/Capture/ScreenCaster.cs index 98be82c8..39fe8af8 100644 --- a/Remotely_ScreenCast/Capture/ScreenCaster.cs +++ b/Remotely_ScreenCast/Capture/ScreenCaster.cs @@ -62,7 +62,7 @@ namespace Remotely_ScreenCast.Capture } await outgoingMessages.SendScreenCount( - Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen), + viewer.CurrentScreenIndex, Screen.AllScreens.Length, viewerID); diff --git a/Remotely_ScreenCast/Utilities/Logger.cs b/Remotely_ScreenCast/Utilities/Logger.cs index 6a219c84..96982575 100644 --- a/Remotely_ScreenCast/Utilities/Logger.cs +++ b/Remotely_ScreenCast/Utilities/Logger.cs @@ -30,7 +30,17 @@ namespace Remotely_ScreenCast.Utilities fi = new FileInfo(path); } } - File.AppendAllText(path, JsonConvert.SerializeObject(jsoninfo) + Environment.NewLine); + try + { + File.AppendAllText(path, JsonConvert.SerializeObject(jsoninfo) + Environment.NewLine); + } + catch + { + Task.Delay(1000).ContinueWith((Task task) => + { + Write(message); + }); + } } public static void Write(Exception ex)