Convert ScreenCast.Win to .NET Core.

This commit is contained in:
Jared Goodwin 2019-12-22 22:05:36 -08:00
parent 2390b67201
commit 21e670ca66
25 changed files with 1485 additions and 321 deletions

View File

@ -6,8 +6,6 @@
<AssemblyName>Remotely_Desktop</AssemblyName>
<RootNamespace>Remotely.Desktop.Linux</RootNamespace>
<Platforms>AnyCPU;x64;x86</Platforms>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishDir>..\Server\wwwroot\Downloads</PublishDir>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>True</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishDir>..\Server\wwwroot\Downloads</PublishDir>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>True</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -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

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishDir>..\Agent\bin\Release\netcoreapp3.1\linux-x64\publish\ScreenCast</PublishDir>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>True</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -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

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishDir>..\Agent\bin\Release\netcoreapp3.1\win10-x64\publish\ScreenCast</PublishDir>
<SelfContained>false</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>True</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishDir>..\Agent\bin\Release\netcoreapp3.1\win10-x86\publish\ScreenCast</PublishDir>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>True</PublishSingleFile>
<PublishReadyToRun>False</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@ -1,287 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}</ProjectGuid>
<OutputType>Exe</OutputType>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<RootNamespace>Remotely.ScreenCast.Win</RootNamespace>
<AssemblyName>Remotely_ScreenCast</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<TargetZone>LocalIntranet</TargetZone>
</PropertyGroup>
<PropertyGroup>
<GenerateManifests>true</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="MessagePack, Version=1.8.0.0, Culture=neutral, PublicKeyToken=b4a0369545f0a1be, processorArchitecture=MSIL">
<HintPath>..\packages\MessagePack.1.8.80\lib\net47\MessagePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Connections.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Connections.Client, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Connections.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Client.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Connections.Common, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Connections.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Features, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Features.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Client, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Client.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Client.Core.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Common, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.Json, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Protocols.Json.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="NAudio, Version=1.9.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.1.9.0\lib\net35\NAudio.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct3D11, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll</HintPath>
</Reference>
<Reference Include="SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Common, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Common.4.7.0\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.IO.Pipelines, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Pipelines.4.7.0\lib\netstandard2.0\System.IO.Pipelines.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Runtime.Serialization.Primitives, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.4.7.0\lib\netstandard2.0\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.4.7.0\lib\net461\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Channels, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<PackageReference Include="NAudio" Version="1.9.0" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="SharpDX.DXGI" Version="4.2.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="Services\WinAudioCapturer.cs" />
<Compile Include="Capture\BitBltCapture.cs" />
<Compile Include="Services\WinClipboardService.cs" />
<Compile Include="Services\CursorIconWatcher.cs" />
<Compile Include="Capture\DXCapture.cs" />
<Compile Include="Services\WinScreenCaster.cs" />
<Compile Include="Services\WinInput.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<ProjectReference Include="..\ScreenCast.Core\ScreenCast.Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ScreenCast.Core\ScreenCast.Core.csproj">
<Project>{b04a1728-2e87-491e-bc7f-f575a1754def}</Project>
<Name>ScreenCast.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Shared\Shared.csproj">
<Project>{3b1b36ae-7a60-4974-a868-1e24894d4149}</Project>
<Name>Shared</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>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\"
)
)</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -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<Rectangle> 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);
}
}
}
}

View File

@ -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<Rectangle> 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<Texture2D>())
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<Output1>();
// 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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -0,0 +1,287 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2DCEA1F5-9B64-4EDB-9CD0-4D6675D96709}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Remotely.ScreenCast.Win</RootNamespace>
<AssemblyName>Remotely_ScreenCast</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<TargetZone>LocalIntranet</TargetZone>
</PropertyGroup>
<PropertyGroup>
<GenerateManifests>true</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="MessagePack, Version=1.8.0.0, Culture=neutral, PublicKeyToken=b4a0369545f0a1be, processorArchitecture=MSIL">
<HintPath>..\packages\MessagePack.1.8.80\lib\net47\MessagePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Connections.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Connections.Client, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Connections.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Client.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Connections.Common, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Connections.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Features, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Features.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Client, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Client.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Client.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Client.Core.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Client.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Common, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Common.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Common.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.Json, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Protocols.Json.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.3.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="NAudio, Version=1.9.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.1.9.0\lib\net35\NAudio.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct3D11, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll</HintPath>
</Reference>
<Reference Include="SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Common, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Common.4.7.0\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.IO.Pipelines, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Pipelines.4.7.0\lib\netstandard2.0\System.IO.Pipelines.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Runtime.Serialization.Primitives, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.4.7.0\lib\netstandard2.0\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.4.7.0\lib\net461\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Channels, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Services\WinAudioCapturer.cs" />
<Compile Include="Capture\BitBltCapture.cs" />
<Compile Include="Services\WinClipboardService.cs" />
<Compile Include="Services\CursorIconWatcher.cs" />
<Compile Include="Capture\DXCapture.cs" />
<Compile Include="Services\WinScreenCaster.cs" />
<Compile Include="Services\WinInput.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ScreenCast.Core\ScreenCast.Core.csproj">
<Project>{b04a1728-2e87-491e-bc7f-f575a1754def}</Project>
<Name>ScreenCast.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Shared\Shared.csproj">
<Project>{3b1b36ae-7a60-4974-a868-1e24894d4149}</Project>
<Name>Shared</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>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\"
)
)</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -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
{
/// <summary>
/// A class that can be used to watch for cursor icon changes.
/// </summary>
public class CursorIconWatcher
{
public CursorIconWatcher(Conductor conductor)
{
Conductor = conductor;
ChangeTimer = new System.Timers.Timer(25);
ChangeTimer.Elapsed += ChangeTimer_Elapsed;
ChangeTimer.Start();
}
public event EventHandler<CursorInfo> 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"));
}
}
}
}

View File

@ -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<byte> TempBuffer { get; set; } = new List<byte>();
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();
}
}
}

View File

@ -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<string> 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();
}
}
}

View File

@ -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<double, double> 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<double, double>(absoluteX / capturer.GetVirtualScreenBounds().Width, absoluteY / capturer.GetVirtualScreenBounds().Height);
}
public Tuple<double, double> 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<double, double>(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;
}
}
}

View File

@ -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<string>() { 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;
}
}
}

View File

@ -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"
}