diff --git a/Desktop.Linux/Desktop.Linux.csproj b/Desktop.Linux/Desktop.Linux.csproj
index efc3e6cc..53b5bee8 100644
--- a/Desktop.Linux/Desktop.Linux.csproj
+++ b/Desktop.Linux/Desktop.Linux.csproj
@@ -6,8 +6,6 @@
Remotely_Desktop
Remotely.Desktop.Linux
AnyCPU;x64;x86
- true
- linux-x64
diff --git a/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml b/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml
new file mode 100644
index 00000000..d1c51966
--- /dev/null
+++ b/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp3.1
+ ..\Server\wwwroot\Downloads
+ linux-x64
+ false
+ True
+ False
+
+
\ No newline at end of file
diff --git a/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml b/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml
new file mode 100644
index 00000000..b45e09ac
--- /dev/null
+++ b/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp3.1
+ ..\Server\wwwroot\Downloads
+ win-x86
+ false
+ True
+ False
+
+
\ No newline at end of file
diff --git a/Remotely.sln b/Remotely.sln
index 80828c63..27d50e76 100644
--- a/Remotely.sln
+++ b/Remotely.sln
@@ -27,11 +27,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Assets", "Assets", "{D96B47
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{3E835099-C417-4D82-8D5C-13DC09AF48AC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenCast.Win", "ScreenCast.Win\ScreenCast.Win.csproj", "{2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}"
- ProjectSection(ProjectDependencies) = postProject
- {98A8DF30-0993-4B49-822E-244A70AB8C4D} = {98A8DF30-0993-4B49-822E-244A70AB8C4D}
- EndProjectSection
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenCast.Linux", "ScreenCast.Linux\ScreenCast.Linux.csproj", "{E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenCast.Core", "ScreenCast.Core\ScreenCast.Core.csproj", "{B04A1728-2E87-491E-BC7F-F575A1754DEF}"
@@ -40,7 +35,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Linux", "Desktop.Linux\Desktop.Linux.csproj", "{FF7FD66A-B3E2-4D39-A457-A00C94EDE9E6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Desktop.Win", "Desktop.Win\Desktop.Win.csproj", "{90530ADC-69C6-4230-A09B-376B34F66B45}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Win", "Desktop.Win\Desktop.Win.csproj", "{90530ADC-69C6-4230-A09B-376B34F66B45}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenCast.Win", "ScreenCast.Win\ScreenCast.Win.csproj", "{D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -76,18 +73,6 @@ Global
{3E835099-C417-4D82-8D5C-13DC09AF48AC}.Release|x64.Build.0 = Release|x64
{3E835099-C417-4D82-8D5C-13DC09AF48AC}.Release|x86.ActiveCfg = Release|x86
{3E835099-C417-4D82-8D5C-13DC09AF48AC}.Release|x86.Build.0 = Release|x86
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Debug|x64.ActiveCfg = Debug|x64
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Debug|x64.Build.0 = Debug|x64
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Debug|x86.ActiveCfg = Debug|x86
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Debug|x86.Build.0 = Debug|x86
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Release|Any CPU.Build.0 = Release|Any CPU
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Release|x64.ActiveCfg = Release|x64
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Release|x64.Build.0 = Release|x64
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Release|x86.ActiveCfg = Release|x86
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}.Release|x86.Build.0 = Release|x86
{E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E46F11D0-3C88-4D43-8CCC-EE7182CAD5C1}.Debug|x64.ActiveCfg = Debug|x64
@@ -148,6 +133,18 @@ Global
{90530ADC-69C6-4230-A09B-376B34F66B45}.Release|x64.Build.0 = Release|Any CPU
{90530ADC-69C6-4230-A09B-376B34F66B45}.Release|x86.ActiveCfg = Release|Any CPU
{90530ADC-69C6-4230-A09B-376B34F66B45}.Release|x86.Build.0 = Release|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Debug|x64.Build.0 = Debug|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Debug|x86.Build.0 = Debug|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Release|x64.ActiveCfg = Release|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Release|x64.Build.0 = Release|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Release|x86.ActiveCfg = Release|Any CPU
+ {D4DE7CAB-74BB-4565-98DF-67DEA2B735FB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/ScreenCast.Linux/Properties/PublishProfiles/linux-x64.pubxml b/ScreenCast.Linux/Properties/PublishProfiles/linux-x64.pubxml
new file mode 100644
index 00000000..c0d31222
--- /dev/null
+++ b/ScreenCast.Linux/Properties/PublishProfiles/linux-x64.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp3.1
+ ..\Agent\bin\Release\netcoreapp3.1\linux-x64\publish\ScreenCast
+ linux-x64
+ false
+ True
+ False
+
+
\ No newline at end of file
diff --git a/ScreenCast.Win/Capture/DXCapture.cs b/ScreenCast.Win/Capture/DXCapture.cs
index 98899211..2e5ec444 100644
--- a/ScreenCast.Win/Capture/DXCapture.cs
+++ b/ScreenCast.Win/Capture/DXCapture.cs
@@ -54,12 +54,12 @@ namespace Remotely.ScreenCast.Win.Capture
OutputDuplicateFrameInformation duplicateFrameInformation;
// Try to get duplicated frame within given time is ms
- duplicatedOutput.AcquireNextFrame(50, out duplicateFrameInformation, out screenResource);
+ duplicatedOutput.TryAcquireNextFrame(50, out duplicateFrameInformation, out screenResource);
while (duplicateFrameInformation.AccumulatedFrames < 1)
{
duplicatedOutput.ReleaseFrame();
- duplicatedOutput.AcquireNextFrame(50, out duplicateFrameInformation, out screenResource);
+ duplicatedOutput.TryAcquireNextFrame(50, out duplicateFrameInformation, out screenResource);
}
// copy resource into memory that can be accessed by the CPU
diff --git a/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml b/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml
new file mode 100644
index 00000000..c413acfa
--- /dev/null
+++ b/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp3.1
+ ..\Agent\bin\Release\netcoreapp3.1\win10-x64\publish\ScreenCast
+ false
+ win-x64
+ True
+ False
+
+
\ No newline at end of file
diff --git a/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml b/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml
new file mode 100644
index 00000000..bfff9bca
--- /dev/null
+++ b/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp3.1
+ ..\Agent\bin\Release\netcoreapp3.1\win10-x86\publish\ScreenCast
+ win-x86
+ false
+ True
+ False
+
+
\ No newline at end of file
diff --git a/ScreenCast.Win/ScreenCast.Win.csproj b/ScreenCast.Win/ScreenCast.Win.csproj
index be467bae..6281cdc5 100644
--- a/ScreenCast.Win/ScreenCast.Win.csproj
+++ b/ScreenCast.Win/ScreenCast.Win.csproj
@@ -1,287 +1,21 @@
-
-
-
+
+
- Debug
- AnyCPU
- {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}
- Exe
+ WinExe
+ netcoreapp3.1
+ true
Remotely.ScreenCast.Win
Remotely_ScreenCast
- v4.8
- 512
- true
- true
-
-
- publish\
- true
- Disk
- false
- Foreground
- 7
- Days
- false
- false
- true
- 0
- 1.0.0.%2a
- false
- false
- true
-
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- true
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- true
-
-
- true
- bin\x64\Debug\
- DEBUG;TRACE
- true
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- bin\x64\Release\
- TRACE
- true
- true
- pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- true
- bin\x86\Debug\
- DEBUG;TRACE
- true
- full
- x86
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- bin\x86\Release\
- TRACE
- true
- true
- pdbonly
- x86
- prompt
- MinimumRecommendedRules.ruleset
- true
-
-
- LocalIntranet
-
-
- true
-
-
- Properties\app.manifest
+
-
- ..\packages\MessagePack.1.8.80\lib\net47\MessagePack.dll
-
-
- ..\packages\Microsoft.AspNetCore.Connections.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll
-
-
- ..\packages\Microsoft.AspNetCore.Http.Connections.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Client.dll
-
-
- ..\packages\Microsoft.AspNetCore.Http.Connections.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll
-
-
- ..\packages\Microsoft.AspNetCore.Http.Features.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll
-
-
- ..\packages\Microsoft.AspNetCore.SignalR.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.dll
-
-
- ..\packages\Microsoft.AspNetCore.SignalR.Client.Core.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.Core.dll
-
-
- ..\packages\Microsoft.AspNetCore.SignalR.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll
-
-
- ..\packages\Microsoft.AspNetCore.SignalR.Protocols.Json.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll
-
-
- ..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll
-
-
- ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- ..\packages\Microsoft.Extensions.Configuration.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll
-
-
- ..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll
-
-
- ..\packages\Microsoft.Extensions.Configuration.Binder.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll
-
-
- ..\packages\Microsoft.Extensions.DependencyInjection.3.1.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll
-
-
- ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll
-
-
- ..\packages\Microsoft.Extensions.Logging.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll
-
-
- ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll
-
-
- ..\packages\Microsoft.Extensions.Options.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll
-
-
- ..\packages\Microsoft.Extensions.Primitives.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll
-
-
- ..\packages\NAudio.1.9.0\lib\net35\NAudio.dll
-
-
- ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
-
-
- ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
-
-
- ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
-
-
-
- ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll
-
-
- ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll
-
-
-
-
-
- ..\packages\System.Drawing.Common.4.7.0\lib\net461\System.Drawing.Common.dll
-
-
- ..\packages\System.IO.Pipelines.4.7.0\lib\netstandard2.0\System.IO.Pipelines.dll
-
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
-
-
-
- ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
-
-
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
-
-
-
- ..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll
- True
- True
-
-
- ..\packages\System.Text.Encodings.Web.4.7.0\lib\netstandard2.0\System.Text.Encodings.Web.dll
-
-
- ..\packages\System.Text.Json.4.7.0\lib\net461\System.Text.Json.dll
-
-
- ..\packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll
-
-
- ..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
-
-
- ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
- {b04a1728-2e87-491e-bc7f-f575a1754def}
- ScreenCast.Core
-
-
- {3b1b36ae-7a60-4974-a868-1e24894d4149}
- Shared
-
-
-
-
- False
- Microsoft .NET Framework 4.7.2 %28x86 and x64%29
- true
-
-
- False
- .NET Framework 3.5 SP1
- false
-
-
-
-
-
-
-
-
- if $(ConfigurationName) == Debug (
- if $(PlatformName) == Any CPU (
- md "$(SolutionDir)Agent\bin\Debug\netcoreapp3.1\ScreenCast\"
- copy /y "$(TargetDir)\*" "$(SolutionDir)Agent\bin\Debug\netcoreapp3.1\ScreenCast\"
- )
-)
-
+
\ No newline at end of file
diff --git a/ScreenCast.Win/App.config b/ScreenCast.Win_Old/App.config
similarity index 100%
rename from ScreenCast.Win/App.config
rename to ScreenCast.Win_Old/App.config
diff --git a/ScreenCast.Win_Old/Capture/BitBltCapture.cs b/ScreenCast.Win_Old/Capture/BitBltCapture.cs
new file mode 100644
index 00000000..adf6b593
--- /dev/null
+++ b/ScreenCast.Win_Old/Capture/BitBltCapture.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Forms;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Remotely.ScreenCast.Core.Services;
+using System.Threading;
+using Remotely.ScreenCast.Core.Interfaces;
+
+namespace Remotely.ScreenCast.Win.Capture
+{
+ public class BitBltCapture : ICapturer
+ {
+ public BitBltCapture()
+ {
+ Init();
+ }
+
+ public bool CaptureFullscreen { get; set; } = true;
+ public Bitmap CurrentFrame { get; set; }
+ public Rectangle CurrentScreenBounds { get; set; } = Screen.PrimaryScreen.Bounds;
+ public bool IsCapturing { get; set; }
+ public int PauseForMilliseconds { get; set; }
+ public Bitmap PreviousFrame { get; set; }
+ public event EventHandler ScreenChanged;
+ public int SelectedScreen { get; private set; } = Screen.AllScreens.ToList().IndexOf(Screen.PrimaryScreen);
+ private Graphics Graphic { get; set; }
+
+ private object ScreenLock { get; } = new object();
+
+ public void Capture()
+ {
+ try
+ {
+ lock (ScreenLock)
+ {
+ PreviousFrame = (Bitmap)CurrentFrame.Clone();
+ Graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height));
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ Init();
+ }
+ }
+
+ public void Dispose()
+ {
+ Graphic.Dispose();
+ CurrentFrame.Dispose();
+ PreviousFrame.Dispose();
+ }
+
+ public int GetScreenCount()
+ {
+ return Screen.AllScreens.Length;
+ }
+
+ public Rectangle GetVirtualScreenBounds()
+ {
+ return SystemInformation.VirtualScreen;
+ }
+
+ public void Init()
+ {
+ CurrentFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
+ PreviousFrame = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb);
+ Graphic = Graphics.FromImage(CurrentFrame);
+ }
+
+ public void SetSelectedScreen(int screenNumber)
+ {
+ if (screenNumber == SelectedScreen)
+ {
+ return;
+ }
+ lock (ScreenLock)
+ {
+ if (GetScreenCount() >= screenNumber + 1)
+ {
+ SelectedScreen = screenNumber;
+ }
+ else
+ {
+ SelectedScreen = 0;
+ }
+ CurrentScreenBounds = Screen.AllScreens[SelectedScreen].Bounds;
+ CaptureFullscreen = true;
+ Init();
+ ScreenChanged?.Invoke(this, CurrentScreenBounds);
+ }
+ }
+ }
+}
diff --git a/ScreenCast.Win_Old/Capture/DXCapture.cs b/ScreenCast.Win_Old/Capture/DXCapture.cs
new file mode 100644
index 00000000..98899211
--- /dev/null
+++ b/ScreenCast.Win_Old/Capture/DXCapture.cs
@@ -0,0 +1,214 @@
+using Remotely.ScreenCast.Core.Interfaces;
+using Remotely.ScreenCast.Core.Services;
+using SharpDX;
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Linq;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace Remotely.ScreenCast.Win.Capture
+{
+ public class DXCapture : ICapturer
+ {
+ private Adapter1 adapter;
+ private SharpDX.Direct3D11.Device device;
+ private OutputDuplication duplicatedOutput;
+ private Factory1 factory;
+ private int height;
+ private Output output;
+ private Output1 output1;
+ private Texture2D screenTexture;
+ private Texture2DDescription textureDesc;
+ private int width;
+ public bool CaptureFullscreen { get; set; } = true;
+ public Bitmap CurrentFrame { get; set; }
+ public Rectangle CurrentScreenBounds { get; private set; }
+ public bool NeedsInit { get; set; } = true;
+ public Bitmap PreviousFrame { get; set; }
+ public event EventHandler ScreenChanged;
+ public int SelectedScreen { get; private set; } = 0;
+
+ public DXCapture()
+ {
+ Init();
+ }
+
+ public void Capture()
+ {
+ try
+ {
+ if (NeedsInit)
+ {
+ duplicatedOutput?.Dispose();
+ Init();
+ }
+
+ PreviousFrame = (Bitmap)CurrentFrame.Clone();
+
+ SharpDX.DXGI.Resource screenResource;
+ OutputDuplicateFrameInformation duplicateFrameInformation;
+
+ // 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);
+ }
+
+ // 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);
+
+ // 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);
+
+ // 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);
+
+ screenResource.Dispose();
+ duplicatedOutput.ReleaseFrame();
+
+ CurrentFrame = (Bitmap)bitmap.Clone();
+ }
+ }
+ catch (SharpDXException e)
+ {
+ if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
+ {
+ Logger.Write(e);
+ NeedsInit = true;
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.Write(e);
+ NeedsInit = true;
+ }
+ }
+
+ public void Dispose()
+ {
+ duplicatedOutput?.Dispose();
+ output1?.Dispose();
+ output?.Dispose();
+ device?.Dispose();
+ adapter?.Dispose();
+ factory?.Dispose();
+ CurrentFrame?.Dispose();
+ PreviousFrame?.Dispose();
+ }
+
+ public int GetScreenCount()
+ {
+ return Screen.AllScreens.Length;
+ }
+
+ public Rectangle GetVirtualScreenBounds()
+ {
+ return SystemInformation.VirtualScreen;
+ }
+
+ public void Init()
+ {
+ 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)
+ {
+ SelectedScreen = 0;
+ }
+ output = adapter.GetOutput(SelectedScreen);
+ output1 = output.QueryInterface();
+
+ // Width/Height of desktop to capture
+ var bounds = output1.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, PixelFormat.Format32bppArgb);
+ PreviousFrame = new Bitmap(width, height, PixelFormat.Format32bppArgb);
+
+ // 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);
+
+ NeedsInit = false;
+ }
+
+ public void SetSelectedScreen(int screenNumber)
+ {
+ if (screenNumber == SelectedScreen)
+ {
+ return;
+ }
+ if (adapter == null)
+ {
+ SelectedScreen = 0;
+ }
+ else
+ {
+ if (adapter.Outputs.Length >= screenNumber + 1)
+ {
+ SelectedScreen = screenNumber;
+ }
+ else
+ {
+ SelectedScreen = 0;
+ }
+ }
+ CaptureFullscreen = true;
+ NeedsInit = true;
+ }
+ }
+}
diff --git a/ScreenCast.Win/FodyWeavers.xml b/ScreenCast.Win_Old/FodyWeavers.xml
similarity index 100%
rename from ScreenCast.Win/FodyWeavers.xml
rename to ScreenCast.Win_Old/FodyWeavers.xml
diff --git a/ScreenCast.Win/FodyWeavers.xsd b/ScreenCast.Win_Old/FodyWeavers.xsd
similarity index 100%
rename from ScreenCast.Win/FodyWeavers.xsd
rename to ScreenCast.Win_Old/FodyWeavers.xsd
diff --git a/ScreenCast.Win_Old/Program.cs b/ScreenCast.Win_Old/Program.cs
new file mode 100644
index 00000000..7b6e6d66
--- /dev/null
+++ b/ScreenCast.Win_Old/Program.cs
@@ -0,0 +1,122 @@
+using Remotely.Shared.Models;
+using Remotely.ScreenCast.Core;
+using Remotely.ScreenCast.Core.Services;
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Remotely.Shared.Win32;
+using System.Threading;
+using Remotely.ScreenCast.Win.Services;
+using Remotely.ScreenCast.Core.Interfaces;
+using Remotely.ScreenCast.Win.Capture;
+using Remotely.ScreenCast.Core.Sockets;
+
+namespace Remotely.ScreenCast.Win
+{
+ public class Program
+ {
+ public static Conductor Conductor { get; private set; }
+ public static CursorIconWatcher CursorIconWatcher { get; private set; }
+ public static async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
+ {
+ if (Conductor?.CasterSocket != null)
+ {
+ await Conductor.CasterSocket.SendCursorChange(cursor, Conductor.Viewers.Keys.ToList());
+ }
+ }
+
+ public static void Main(string[] args)
+ {
+ try
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ CursorIconWatcher = new CursorIconWatcher(Conductor);
+ var screenCaster = new WinScreenCaster(CursorIconWatcher);
+ var clipboardService = new WinClipboardService();
+ clipboardService.BeginWatching();
+ var casterSocket = new CasterSocket(new WinInput(), screenCaster, new WinAudioCapturer(), clipboardService);
+ Conductor = new Conductor(casterSocket, screenCaster);
+ Conductor.ProcessArgs(args);
+
+ Conductor.Connect().ContinueWith(async (task) =>
+ {
+ CursorIconWatcher.OnChange += CursorIconWatcher_OnChange;
+ await Conductor.CasterSocket.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName, Conductor.DeviceID);
+ CheckInitialDesktop();
+ await CheckForRelaunch();
+ Conductor.IdleTimer = new IdleTimer(Conductor.Viewers);
+ Conductor.IdleTimer.Start();
+
+ await HandleConnection(Conductor);
+ });
+
+ Thread.Sleep(Timeout.Infinite);
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ throw;
+ }
+ }
+
+ private static async Task CheckForRelaunch()
+ {
+
+ if (Conductor.ArgDict.ContainsKey("relaunch"))
+ {
+ Logger.Write($"Resuming after relaunch in desktop {Conductor.CurrentDesktopName}.");
+ var viewersString = Conductor.ArgDict["viewers"];
+ var viewerIDs = viewersString.Split(",".ToCharArray());
+ await Conductor.CasterSocket.NotifyViewersRelaunchedScreenCasterReady(viewerIDs);
+ }
+ else
+ {
+ await Conductor.CasterSocket.NotifyRequesterUnattendedReady(Conductor.RequesterID);
+ }
+ }
+
+ private static void CheckInitialDesktop()
+ {
+ var desktopName = Win32Interop.GetCurrentDesktop();
+ if (desktopName.ToLower() != Conductor.CurrentDesktopName.ToLower())
+ {
+ Conductor.CurrentDesktopName = desktopName;
+ Logger.Write($"Setting initial desktop to {desktopName}.");
+ Conductor.ArgDict["desktop"] = desktopName;
+ var openProcessString = Assembly.GetExecutingAssembly().Location;
+ foreach (var arg in Conductor.ArgDict)
+ {
+ openProcessString += $" -{arg.Key} {arg.Value}";
+ }
+ var result = Win32Interop.OpenInteractiveProcess(openProcessString, desktopName, true, out _);
+ if (!result)
+ {
+ Logger.Write($"Desktop relaunch to {desktopName} failed.");
+ }
+ Environment.Exit(0);
+ }
+ }
+
+ private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Logger.Write((Exception)e.ExceptionObject);
+ }
+
+
+ private static async Task HandleConnection(Conductor conductor)
+ {
+ while (true)
+ {
+ var desktopName = Win32Interop.GetCurrentDesktop();
+ if (desktopName.ToLower() != conductor.CurrentDesktopName.ToLower() && conductor.Viewers.Count > 0)
+ {
+ conductor.CurrentDesktopName = desktopName;
+ Logger.Write($"Switching desktops to {desktopName}.");
+ Win32Interop.SwitchToInputDesktop();
+ }
+ await Task.Delay(1000);
+ }
+ }
+ }
+}
diff --git a/ScreenCast.Win/Properties/AssemblyInfo.cs b/ScreenCast.Win_Old/Properties/AssemblyInfo.cs
similarity index 100%
rename from ScreenCast.Win/Properties/AssemblyInfo.cs
rename to ScreenCast.Win_Old/Properties/AssemblyInfo.cs
diff --git a/ScreenCast.Win/Properties/app.manifest b/ScreenCast.Win_Old/Properties/app.manifest
similarity index 100%
rename from ScreenCast.Win/Properties/app.manifest
rename to ScreenCast.Win_Old/Properties/app.manifest
diff --git a/ScreenCast.Win_Old/ScreenCast.Win.csproj b/ScreenCast.Win_Old/ScreenCast.Win.csproj
new file mode 100644
index 00000000..be467bae
--- /dev/null
+++ b/ScreenCast.Win_Old/ScreenCast.Win.csproj
@@ -0,0 +1,287 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}
+ Exe
+ Remotely.ScreenCast.Win
+ Remotely_ScreenCast
+ v4.8
+ 512
+ true
+ true
+
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ true
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ true
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ LocalIntranet
+
+
+ true
+
+
+ Properties\app.manifest
+
+
+
+ ..\packages\MessagePack.1.8.80\lib\net47\MessagePack.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Connections.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Http.Connections.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Client.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Http.Connections.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll
+
+
+ ..\packages\Microsoft.AspNetCore.Http.Features.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Client.Core.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.Core.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Protocols.Json.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll
+
+
+ ..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll
+
+
+ ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
+
+
+ ..\packages\Microsoft.Extensions.Configuration.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll
+
+
+ ..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll
+
+
+ ..\packages\Microsoft.Extensions.Configuration.Binder.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll
+
+
+ ..\packages\Microsoft.Extensions.DependencyInjection.3.1.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll
+
+
+ ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll
+
+
+ ..\packages\Microsoft.Extensions.Logging.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll
+
+
+ ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll
+
+
+ ..\packages\Microsoft.Extensions.Options.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll
+
+
+ ..\packages\Microsoft.Extensions.Primitives.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll
+
+
+ ..\packages\NAudio.1.9.0\lib\net35\NAudio.dll
+
+
+ ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
+
+
+ ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll
+
+
+ ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll
+
+
+
+ ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll
+
+
+ ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll
+
+
+
+
+
+ ..\packages\System.Drawing.Common.4.7.0\lib\net461\System.Drawing.Common.dll
+
+
+ ..\packages\System.IO.Pipelines.4.7.0\lib\netstandard2.0\System.IO.Pipelines.dll
+
+
+ ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+
+ ..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll
+ True
+ True
+
+
+ ..\packages\System.Text.Encodings.Web.4.7.0\lib\netstandard2.0\System.Text.Encodings.Web.dll
+
+
+ ..\packages\System.Text.Json.4.7.0\lib\net461\System.Text.Json.dll
+
+
+ ..\packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
+
+
+ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {b04a1728-2e87-491e-bc7f-f575a1754def}
+ ScreenCast.Core
+
+
+ {3b1b36ae-7a60-4974-a868-1e24894d4149}
+ Shared
+
+
+
+
+ False
+ Microsoft .NET Framework 4.7.2 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+
+
+
+ if $(ConfigurationName) == Debug (
+ if $(PlatformName) == Any CPU (
+ md "$(SolutionDir)Agent\bin\Debug\netcoreapp3.1\ScreenCast\"
+ copy /y "$(TargetDir)\*" "$(SolutionDir)Agent\bin\Debug\netcoreapp3.1\ScreenCast\"
+ )
+)
+
+
\ No newline at end of file
diff --git a/ScreenCast.Win_Old/Services/CursorIconWatcher.cs b/ScreenCast.Win_Old/Services/CursorIconWatcher.cs
new file mode 100644
index 00000000..43d2709d
--- /dev/null
+++ b/ScreenCast.Win_Old/Services/CursorIconWatcher.cs
@@ -0,0 +1,128 @@
+using Remotely.ScreenCast.Core;
+using Remotely.ScreenCast.Core.Models;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Timers;
+using System.Windows.Forms;
+using Remotely.Shared.Win32;
+using Remotely.Shared.Models;
+
+namespace Remotely.ScreenCast.Win.Services
+{
+ ///
+ /// A class that can be used to watch for cursor icon changes.
+ ///
+ public class CursorIconWatcher
+ {
+ public CursorIconWatcher(Conductor conductor)
+ {
+ Conductor = conductor;
+ ChangeTimer = new System.Timers.Timer(25);
+ ChangeTimer.Elapsed += ChangeTimer_Elapsed;
+ ChangeTimer.Start();
+ }
+ public event EventHandler OnChange;
+ private System.Timers.Timer ChangeTimer { get; set; }
+ private string PreviousCursorHandle { get; set; }
+ public Conductor Conductor { get; }
+
+ private User32.CursorInfo cursorInfo;
+
+
+ public CursorInfo GetCurrentCursor()
+ {
+ try
+ {
+ var ci = new User32.CursorInfo();
+ ci.cbSize = Marshal.SizeOf(ci);
+ User32.GetCursorInfo(out ci);
+ if (ci.flags == User32.CURSOR_SHOWING)
+ {
+ if (ci.hCursor.ToString() == Cursors.IBeam.Handle.ToString())
+ {
+ return new CursorInfo(new byte[0], Point.Empty, "text");
+ }
+
+ using (var icon = Icon.FromHandle(ci.hCursor))
+ {
+ using (var ms = new MemoryStream())
+ {
+ using (var cursor = new Cursor(ci.hCursor))
+ {
+ var hotspot = cursor.HotSpot;
+ icon.ToBitmap().Save(ms, ImageFormat.Png);
+ return new CursorInfo(ms.ToArray(), hotspot);
+ }
+ }
+ }
+ }
+ else
+ {
+ return new CursorInfo(new byte[0], Point.Empty, "default");
+ }
+ }
+ catch
+ {
+ return new CursorInfo(new byte[0], Point.Empty, "default");
+ }
+ }
+
+ private void ChangeTimer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ if (OnChange == null)
+ {
+ return;
+ }
+ try
+ {
+ cursorInfo = new User32.CursorInfo();
+ cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
+ User32.GetCursorInfo(out cursorInfo);
+ if (cursorInfo.flags == User32.CURSOR_SHOWING)
+ {
+ var currentCursor = cursorInfo.hCursor.ToString();
+ if (currentCursor != PreviousCursorHandle)
+ {
+ if (currentCursor == Cursors.IBeam.Handle.ToString())
+ {
+ OnChange?.Invoke(this, new CursorInfo(new byte[0], Point.Empty, "text"));
+ }
+ else
+ {
+ using (var icon = Icon.FromHandle(cursorInfo.hCursor))
+ {
+ using (var ms = new MemoryStream())
+ {
+ using (var cursor = new Cursor(cursorInfo.hCursor))
+ {
+ var hotspot = cursor.HotSpot;
+ icon.ToBitmap().Save(ms, ImageFormat.Png);
+ OnChange?.Invoke(this, new CursorInfo(ms.ToArray(), hotspot));
+ }
+ }
+ }
+ }
+ PreviousCursorHandle = currentCursor;
+ }
+ }
+ else if (PreviousCursorHandle != "0")
+ {
+ PreviousCursorHandle = "0";
+ OnChange?.Invoke(this, new CursorInfo(new byte[0], Point.Empty, "default"));
+ }
+ }
+ catch
+ {
+ OnChange?.Invoke(this, new CursorInfo(new byte[0], Point.Empty, "default"));
+ }
+ }
+
+ }
+}
diff --git a/ScreenCast.Win_Old/Services/WinAudioCapturer.cs b/ScreenCast.Win_Old/Services/WinAudioCapturer.cs
new file mode 100644
index 00000000..f6dca2da
--- /dev/null
+++ b/ScreenCast.Win_Old/Services/WinAudioCapturer.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Timers;
+using NAudio.Wave;
+using Remotely.ScreenCast.Core;
+using Remotely.ScreenCast.Core.Interfaces;
+
+namespace Remotely.ScreenCast.Win.Services
+{
+ public class WinAudioCapturer : IAudioCapturer
+ {
+ private WasapiLoopbackCapture Capturer { get; set; }
+ private Stopwatch SendTimer { get; set; }
+ private WaveFormat TargetFormat { get; set; }
+ private List TempBuffer { get; set; } = new List();
+ public void ToggleAudio(bool toggleOn)
+ {
+ if (toggleOn)
+ {
+ Start();
+ }
+ else
+ {
+ Stop();
+ }
+ }
+
+ private async void SendTempBuffer()
+ {
+ if (TempBuffer.Count == 0)
+ {
+ return;
+ }
+
+ using (var ms1 = new MemoryStream())
+ {
+ using (var wfw = new WaveFileWriter(ms1, Capturer.WaveFormat))
+ {
+ wfw.Write(TempBuffer.ToArray(), 0, TempBuffer.Count);
+ }
+ TempBuffer.Clear();
+
+ // Resample to 16-bit so Firefox will play it.
+ using (var ms2 = new MemoryStream(ms1.ToArray()))
+ using (var wfr = new WaveFileReader(ms2))
+ using (var ms3 = new MemoryStream())
+ {
+ using (var resampler = new MediaFoundationResampler(wfr, TargetFormat))
+ {
+ WaveFileWriter.WriteWavFileToStream(ms3, resampler);
+ }
+ await Conductor.Current.CasterSocket.SendAudioSample(ms3.ToArray(), Program.Conductor.Viewers.Keys.ToList());
+ }
+ }
+ }
+
+ private void Start()
+ {
+ try
+ {
+ Capturer = new WasapiLoopbackCapture();
+ TargetFormat = new WaveFormat(16000, 8, 1);
+ SendTimer = Stopwatch.StartNew();
+ Capturer.DataAvailable += (aud, args) =>
+ {
+ try
+ {
+ if (args.BytesRecorded > 0)
+ {
+ lock (TempBuffer)
+ {
+ if (!SendTimer.IsRunning)
+ {
+ SendTimer.Restart();
+ }
+ TempBuffer.AddRange(args.Buffer.Take(args.BytesRecorded));
+ if (TempBuffer.Count > 200000)
+ {
+ SendTimer.Reset();
+ SendTempBuffer();
+ }
+ else if (SendTimer.Elapsed.TotalMilliseconds > 1000)
+ {
+ SendTimer.Reset();
+ SendTempBuffer();
+ }
+ }
+ }
+ }
+ catch { }
+ };
+ Capturer.StartRecording();
+ }
+ catch { }
+ }
+ private void Stop()
+ {
+ Capturer.StopRecording();
+ SendTimer.Reset();
+ }
+ }
+}
diff --git a/ScreenCast.Win_Old/Services/WinClipboardService.cs b/ScreenCast.Win_Old/Services/WinClipboardService.cs
new file mode 100644
index 00000000..3c8c3552
--- /dev/null
+++ b/ScreenCast.Win_Old/Services/WinClipboardService.cs
@@ -0,0 +1,86 @@
+using Remotely.ScreenCast.Core.Interfaces;
+using Remotely.ScreenCast.Core.Services;
+using Remotely.ScreenCast.Core.Sockets;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Remotely.ScreenCast.Win.Services
+{
+ public class WinClipboardService : IClipboardService
+ {
+ public event EventHandler ClipboardTextChanged;
+
+ private string ClipboardText { get; set; }
+
+ private System.Timers.Timer ClipboardWatcher { get; set; }
+
+ public void BeginWatching()
+ {
+ try
+ {
+ if (ClipboardWatcher?.Enabled == true)
+ {
+ ClipboardWatcher.Stop();
+ }
+
+ if (Clipboard.ContainsText())
+ {
+ ClipboardText = Clipboard.GetText();
+ ClipboardTextChanged.Invoke(this, ClipboardText);
+ }
+ ClipboardWatcher = new System.Timers.Timer(500);
+ }
+ catch
+ {
+ return;
+ }
+ ClipboardWatcher.Elapsed += (sender, args) =>
+ {
+ var thread = new Thread(() =>
+ {
+ try
+ {
+ if (Clipboard.ContainsText() && Clipboard.GetText() != ClipboardText)
+ {
+ ClipboardText = Clipboard.GetText();
+ ClipboardTextChanged.Invoke(this, ClipboardText);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ });
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ };
+ ClipboardWatcher.Start();
+ }
+
+ public void SetText(string clipboardText)
+ {
+ try
+ {
+ var thread = new Thread(() =>
+ {
+ Clipboard.SetText(clipboardText);
+ });
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
+ public void StopWatching()
+ {
+ ClipboardWatcher?.Stop();
+ }
+ }
+}
diff --git a/ScreenCast.Win_Old/Services/WinInput.cs b/ScreenCast.Win_Old/Services/WinInput.cs
new file mode 100644
index 00000000..48798fc5
--- /dev/null
+++ b/ScreenCast.Win_Old/Services/WinInput.cs
@@ -0,0 +1,261 @@
+using Remotely.ScreenCast.Core.Input;
+using Remotely.ScreenCast.Core.Models;
+using System;
+using Remotely.Shared.Win32;
+using static Remotely.Shared.Win32.User32;
+using Remotely.ScreenCast.Core.Capture;
+using Remotely.ScreenCast.Core.Interfaces;
+using System.Windows.Forms;
+
+namespace Remotely.ScreenCast.Win.Services
+{
+ public class WinInput : IKeyboardMouseInput
+ {
+ public Tuple GetAbsolutePercentFromRelativePercent(double percentX, double percentY, ICapturer capturer)
+ {
+ var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left - capturer.GetVirtualScreenBounds().Left;
+ var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top - capturer.GetVirtualScreenBounds().Top;
+ return new Tuple(absoluteX / capturer.GetVirtualScreenBounds().Width, absoluteY / capturer.GetVirtualScreenBounds().Height);
+ }
+
+ public Tuple GetAbsolutePointFromRelativePercent(double percentX, double percentY, ICapturer capturer)
+ {
+ var absoluteX = (capturer.CurrentScreenBounds.Width * percentX) + capturer.CurrentScreenBounds.Left;
+ var absoluteY = (capturer.CurrentScreenBounds.Height * percentY) + capturer.CurrentScreenBounds.Top;
+ return new Tuple(absoluteX, absoluteY);
+ }
+
+ public void SendKeyDown(string key, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var keyCode = ConvertJavaScriptKeyToVirtualKey(key);
+ var union = new InputUnion()
+ {
+ ki = new KEYBDINPUT()
+ {
+ wVk = keyCode,
+ wScan = 0,
+ time = 0,
+ dwExtraInfo = GetMessageExtraInfo()
+ }
+ };
+ var input = new INPUT() { type = InputType.KEYBOARD, U = union };
+ SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+
+ public void SendKeyUp(string key, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var keyCode = ConvertJavaScriptKeyToVirtualKey(key);
+ var union = new InputUnion()
+ {
+ ki = new KEYBDINPUT()
+ {
+ wVk = keyCode,
+ wScan = 0,
+ time = 0,
+ dwFlags = KEYEVENTF.KEYUP,
+ dwExtraInfo = GetMessageExtraInfo()
+ }
+ };
+ var input = new INPUT() { type = InputType.KEYBOARD, U = union };
+ SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+
+ public uint SendLeftMouseDown(double percentX, double percentY, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = xyPercent.Item1 * 65535D;
+ var normalizedY = xyPercent.Item2 * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.LEFTDOWN | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendLeftMouseUp(double percentX, double percentY, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = xyPercent.Item1 * 65535D;
+ var normalizedY = xyPercent.Item2 * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.LEFTUP | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendMouseMove(double percentX, double percentY, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = xyPercent.Item1 * 65535D;
+ var normalizedY = xyPercent.Item2 * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.MOVE | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+
+ public uint SendMouseWheel(int deltaY, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ if (deltaY < 0)
+ {
+ deltaY = -120;
+ }
+ else if (deltaY > 0)
+ {
+ deltaY = 120;
+ }
+ var union = new User32.InputUnion() { mi = new User32.MOUSEINPUT() { dwFlags = MOUSEEVENTF.WHEEL, dx = 0, dy = 0, time = 0, mouseData = deltaY, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new User32.INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new User32.INPUT[] { input }, INPUT.Size);
+ }
+
+ public uint SendRightMouseDown(double percentX, double percentY, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = xyPercent.Item1 * 65535D;
+ var normalizedY = xyPercent.Item2 * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.RIGHTDOWN | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public uint SendRightMouseUp(double percentX, double percentY, Viewer viewer)
+ {
+ Win32Interop.SwitchToInputDesktop();
+ var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, viewer.Capturer);
+ // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535.
+ var normalizedX = xyPercent.Item1 * 65535D;
+ var normalizedY = xyPercent.Item2 * 65535D;
+ var union = new InputUnion() { mi = new MOUSEINPUT() { dwFlags = MOUSEEVENTF.ABSOLUTE | MOUSEEVENTF.RIGHTUP | MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = GetMessageExtraInfo() } };
+ var input = new INPUT() { type = InputType.MOUSE, U = union };
+ return SendInput(1, new INPUT[] { input }, INPUT.Size);
+ }
+ public void SendText(string transferText, Viewer viewer)
+ {
+ SendKeys.SendWait(transferText);
+ }
+
+ private VirtualKey ConvertJavaScriptKeyToVirtualKey(string key)
+ {
+ VirtualKey keyCode;
+ switch (key)
+ {
+ case "Down":
+ case "ArrowDown":
+ keyCode = VirtualKey.DOWN;
+ break;
+ case "Up":
+ case "ArrowUp":
+ keyCode = VirtualKey.UP;
+ break;
+ case "Left":
+ case "ArrowLeft":
+ keyCode = VirtualKey.LEFT;
+ break;
+ case "Right":
+ case "ArrowRight":
+ keyCode = VirtualKey.RIGHT;
+ break;
+ case "Enter":
+ keyCode = VirtualKey.RETURN;
+ break;
+ case "Esc":
+ case "Escape":
+ keyCode = VirtualKey.ESCAPE;
+ break;
+ case "Alt":
+ keyCode = VirtualKey.MENU;
+ break;
+ case "Control":
+ keyCode = VirtualKey.CONTROL;
+ break;
+ case "Shift":
+ keyCode = VirtualKey.SHIFT;
+ break;
+ case "PAUSE":
+ keyCode = VirtualKey.PAUSE;
+ break;
+ case "BREAK":
+ keyCode = VirtualKey.PAUSE;
+ break;
+ case "Backspace":
+ keyCode = VirtualKey.BACK;
+ break;
+ case "Tab":
+ keyCode = VirtualKey.TAB;
+ break;
+ case "CapsLock":
+ keyCode = VirtualKey.CAPITAL;
+ break;
+ case "Delete":
+ keyCode = VirtualKey.DELETE;
+ break;
+ case "Home":
+ keyCode = VirtualKey.HOME;
+ break;
+ case "End":
+ keyCode = VirtualKey.END;
+ break;
+ case "PageUp":
+ keyCode = VirtualKey.PRIOR;
+ break;
+ case "PageDown":
+ keyCode = VirtualKey.NEXT;
+ break;
+ case "NumLock":
+ keyCode = VirtualKey.NUMLOCK;
+ break;
+ case "Insert":
+ keyCode = VirtualKey.INSERT;
+ break;
+ case "ScrollLock":
+ keyCode = VirtualKey.SCROLL;
+ break;
+ case "F1":
+ keyCode = VirtualKey.F1;
+ break;
+ case "F2":
+ keyCode = VirtualKey.F2;
+ break;
+ case "F3":
+ keyCode = VirtualKey.F3;
+ break;
+ case "F4":
+ keyCode = VirtualKey.F4;
+ break;
+ case "F5":
+ keyCode = VirtualKey.F5;
+ break;
+ case "F6":
+ keyCode = VirtualKey.F6;
+ break;
+ case "F7":
+ keyCode = VirtualKey.F7;
+ break;
+ case "F8":
+ keyCode = VirtualKey.F8;
+ break;
+ case "F9":
+ keyCode = VirtualKey.F9;
+ break;
+ case "F10":
+ keyCode = VirtualKey.F10;
+ break;
+ case "F11":
+ keyCode = VirtualKey.F11;
+ break;
+ case "F12":
+ keyCode = VirtualKey.F12;
+ break;
+ default:
+ keyCode = (VirtualKey)VkKeyScan(Convert.ToChar(key));
+ break;
+ }
+ return keyCode;
+ }
+ }
+}
diff --git a/ScreenCast.Win_Old/Services/WinScreenCaster.cs b/ScreenCast.Win_Old/Services/WinScreenCaster.cs
new file mode 100644
index 00000000..7b831ed8
--- /dev/null
+++ b/ScreenCast.Win_Old/Services/WinScreenCaster.cs
@@ -0,0 +1,55 @@
+using Remotely.ScreenCast.Core.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Remotely.ScreenCast.Core.Enums;
+using Remotely.ScreenCast.Core.Services;
+using Remotely.ScreenCast.Core.Capture;
+using Remotely.ScreenCast.Core;
+using Remotely.ScreenCast.Core.Models;
+using Remotely.Shared.Models;
+using Remotely.ScreenCast.Win.Capture;
+
+namespace Remotely.ScreenCast.Win.Services
+{
+ public class WinScreenCaster : ScreenCasterBase, IScreenCaster
+ {
+ public WinScreenCaster(CursorIconWatcher cursorIconWatcher)
+ {
+ CursorIconWatcher = cursorIconWatcher;
+ }
+
+ public CursorIconWatcher CursorIconWatcher { get; }
+
+ public async Task BeginScreenCasting(ScreenCastRequest screenCastRequest)
+ {
+ await Conductor.Current.CasterSocket.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List() { screenCastRequest.ViewerID });
+ _ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, GetCapturer());
+ }
+
+ private static ICapturer GetCapturer()
+ {
+ ICapturer capturer;
+ try
+ {
+ if (Conductor.Current.Viewers.Count == 0)
+ {
+ capturer = new DXCapture();
+ }
+ else
+ {
+ capturer = new BitBltCapture();
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ capturer = new BitBltCapture();
+ }
+
+ return capturer;
+ }
+ }
+}
diff --git a/ScreenCast.Win/packages.config b/ScreenCast.Win_Old/packages.config
similarity index 100%
rename from ScreenCast.Win/packages.config
rename to ScreenCast.Win_Old/packages.config
diff --git a/Utilities/Publish.ps1 b/Utilities/Publish.ps1
index ca6041c8..affe5484 100644
--- a/Utilities/Publish.ps1
+++ b/Utilities/Publish.ps1
@@ -114,9 +114,9 @@ if ((Test-Path -Path "$Root\Agent\bin\Release\netcoreapp3.1\linux-x64\publish")
# Publish Core clients.
-dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime win10-x64 --configuration Release --output "$Root\Agent\bin\Release\netcoreapp3.1\win10-x64\publish" "$Root\Agent"
-dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime linux-x64 --configuration Release --output "$Root\Agent\bin\Release\netcoreapp3.1\linux-x64\publish" "$Root\Agent"
-dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime win10-x86 --configuration Release --output "$Root\Agent\bin\Release\netcoreapp3.1\win10-x86\publish" "$Root\Agent"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime win10-x64 --configuration Release --no-self-contained --output "$Root\Agent\bin\Release\netcoreapp3.1\win10-x64\publish" "$Root\Agent"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime linux-x64 --configuration Release --no-self-contained --output "$Root\Agent\bin\Release\netcoreapp3.1\linux-x64\publish" "$Root\Agent"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime win10-x86 --configuration Release --no-self-contained --output "$Root\Agent\bin\Release\netcoreapp3.1\win10-x86\publish" "$Root\Agent"
New-Item -Path "$Root\Agent\bin\Release\netcoreapp3.1\win10-x64\publish\ScreenCast\" -ItemType Directory -Force
New-Item -Path "$Root\Agent\bin\Release\netcoreapp3.1\win10-x86\publish\ScreenCast\" -ItemType Directory -Force
@@ -124,31 +124,21 @@ New-Item -Path "$Root\Agent\bin\Release\netcoreapp3.1\linux-x64\publish\ScreenCa
# Publish Linux ScreenCaster
-dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime linux-x64 --configuration Release --output "$Root\Agent\bin\Release\netcoreapp3.1\linux-x64\publish\ScreenCast\" "$Root\ScreenCast.Linux\"
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=linux-x64 "$Root\ScreenCast.Linux\"
# Publish Linux GUI App
-$PublishDir = "$Root\Desktop.Linux\bin\Release\netcoreapp3.1\linux-x64\publish\"
-dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion --runtime linux-x64 --configuration Release --output "$PublishDir" "$Root\Desktop.Linux\"
-Move-Item -Path "$PublishDir\Remotely_Desktop" -Destination "$Root\Server\wwwroot\Downloads\Remotely_Desktop" -Force
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=linux-x64 "$Root\Desktop.Linux\"
-# Build .NET Framework ScreenCaster (32-bit)
-&"$MSBuildPath" "$Root\ScreenCast.Win" /t:Build /p:Configuration=Release /p:Platform=x86
+# Publish Windows ScreenCaster (32-bit)
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=win-x86 "$Root\ScreenCast.Win"
-# Copy 32-bit .NET Framework ScreenCaster to Agent output folder.
-Get-ChildItem -Path "$Root\ScreenCast.Win\bin\x86\Release\" -Exclude "*.xml" | Copy-Item -Destination ".\Agent\bin\Release\netcoreapp3.1\win10-x86\publish\ScreenCast\" -Force
+# Publish Windows ScreenCaster (64-bit)
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=win-x64 "$Root\ScreenCast.Win"
-# Build .NET Framework ScreenCaster (64-bit)
-&"$MSBuildPath" "$Root\ScreenCast.Win" /t:Build /p:Configuration=Release /p:Platform=x64
+# Publish Windows GUI App
+dotnet publish /p:Version=$CurrentVersion /p:FileVersion=$CurrentVersion -p:PublishProfile=win-x64 "$Root\ScreenCast.Win"
-# Copy 64-bit .NET Framework ScreenCaster to Agent output folder.
-Get-ChildItem -Path "$Root\ScreenCast.Win\bin\x64\Release\" -Exclude "*.xml" | Copy-Item -Destination ".\Agent\bin\Release\netcoreapp3.1\win10-x64\publish\ScreenCast\" -Force
-
-
-# Build Windows GUI App
-
-&"$MSBuildPath" "$Root\Desktop.Win" /t:Build /p:Configuration=Release /p:Platform=AnyCPU
-Move-Item -Path "$Root\Desktop.Win\bin\Release\Remotely_Desktop.exe" -Destination "$Root\Server\wwwroot\Downloads\Remotely_Desktop.exe" -Force
if ($SignAssemblies) {
&"$Root\Utilities\signtool.exe" sign /f "$CertificatePath" /p $CertificatePassword /t http://timestamp.digicert.com "$Root\Server\wwwroot\Downloads\Remotely_Desktop.exe"
}