mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Add support for Windows 8.1 and 7.
This commit is contained in:
parent
a811f7e04f
commit
b712874eeb
@ -60,7 +60,7 @@ namespace Remotely.Agent.Services
|
||||
|
||||
await HubConnection.StartAsync();
|
||||
|
||||
var device = await Device.Create(ConnectionInfo);
|
||||
var device = await DeviceInformation.Create(ConnectionInfo);
|
||||
|
||||
var result = await HubConnection.InvokeAsync<bool>("DeviceCameOnline", device);
|
||||
|
||||
@ -98,7 +98,7 @@ namespace Remotely.Agent.Services
|
||||
|
||||
public async Task SendHeartbeat()
|
||||
{
|
||||
var currentInfo = await Device.Create(ConnectionInfo);
|
||||
var currentInfo = await DeviceInformation.Create(ConnectionInfo);
|
||||
await HubConnection.InvokeAsync("DeviceHeartbeat", currentInfo);
|
||||
}
|
||||
|
||||
|
||||
@ -43,15 +43,18 @@
|
||||
@if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
<div class="col-sm-6 mb-3">
|
||||
<h6>Windows 10 (64-Bit and 32-Bit)</h6>
|
||||
<h6>Windows 10 / 8.1 / 7 (64-Bit and 32-Bit)</h6>
|
||||
<p>
|
||||
<small>Note: GPU-accelerated screen capture and PowerShell Core is unavailable on Windows 7.</small>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Download:</strong>
|
||||
<br />
|
||||
<a href="/API/ClientDownloads/Windows">Windows 10 Installer (x64/x86)</a>
|
||||
<a href="/API/ClientDownloads/Windows">Windows Installer (x64/x86)</a>
|
||||
<br />
|
||||
<a href="~/Downloads/Remotely-Win10-x64.zip">Windows 10 x64 Files Only</a>
|
||||
<a href="~/Downloads/Remotely-Win10-x64.zip">Windows x64 Files Only</a>
|
||||
<br />
|
||||
<a href="~/Downloads/Remotely-Win10-x86.zip">Windows 10 x86 Files Only</a>
|
||||
<a href="~/Downloads/Remotely-Win10-x86.zip">Windows x86 Files Only</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@ -51,70 +51,7 @@ namespace Remotely.Shared.Models
|
||||
|
||||
public double TotalMemory { get; set; }
|
||||
public double TotalStorage { get; set; }
|
||||
public static async Task<Device> Create(ConnectionInfo connectionInfo)
|
||||
{
|
||||
OSPlatform platform = OSUtils.GetPlatform();
|
||||
DriveInfo systemDrive;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Environment.SystemDirectory))
|
||||
{
|
||||
systemDrive = DriveInfo.GetDrives()
|
||||
.Where(x=>x.IsReady)
|
||||
.FirstOrDefault(x =>
|
||||
x.RootDirectory.FullName.Contains(Path.GetPathRoot(Environment.SystemDirectory ?? Environment.CurrentDirectory))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
systemDrive = DriveInfo.GetDrives().FirstOrDefault(x =>
|
||||
x.IsReady &&
|
||||
x.RootDirectory.FullName == Path.GetPathRoot(Environment.CurrentDirectory));
|
||||
}
|
||||
|
||||
var device = new Device()
|
||||
{
|
||||
ID = connectionInfo.DeviceID,
|
||||
DeviceName = Environment.MachineName,
|
||||
Platform = platform.ToString(),
|
||||
ProcessorCount = Environment.ProcessorCount,
|
||||
OSArchitecture = RuntimeInformation.OSArchitecture,
|
||||
OSDescription = RuntimeInformation.OSDescription,
|
||||
Is64Bit = Environment.Is64BitOperatingSystem,
|
||||
IsOnline = true,
|
||||
Drives = DriveInfo.GetDrives().Where(x => x.IsReady).Select(x => new Drive()
|
||||
{
|
||||
DriveFormat = x.DriveFormat,
|
||||
DriveType = x.DriveType,
|
||||
Name = x.Name,
|
||||
RootDirectory = x.RootDirectory.FullName,
|
||||
FreeSpace = x.TotalSize > 0 ? x.TotalFreeSpace / x.TotalSize : 0,
|
||||
TotalSize = x.TotalSize > 0 ? Math.Round((double)(x.TotalSize / 1024 / 1024 / 1024), 2) : 0,
|
||||
VolumeLabel = x.VolumeLabel
|
||||
}).ToList(),
|
||||
OrganizationID = connectionInfo.OrganizationID,
|
||||
CurrentUser = DeviceInformation.GetCurrentUser()
|
||||
};
|
||||
|
||||
if (systemDrive != null && systemDrive.TotalSize > 0 && systemDrive.TotalFreeSpace > 0)
|
||||
{
|
||||
device.TotalStorage = Math.Round((double)(systemDrive.TotalSize / 1024 / 1024 / 1024), 2);
|
||||
device.UsedStorage = Math.Round((double)((systemDrive.TotalSize - systemDrive.TotalFreeSpace) / 1024 / 1024 / 1024), 2);
|
||||
}
|
||||
|
||||
|
||||
var (usedMemory, totalMemory) = DeviceInformation.GetMemoryInGB();
|
||||
device.UsedMemory = usedMemory;
|
||||
device.TotalMemory = totalMemory;
|
||||
|
||||
device.CpuUtilization = await DeviceInformation.GetCpuUtilization();
|
||||
|
||||
if (File.Exists("Remotely_Agent.dll"))
|
||||
{
|
||||
device.AgentVersion = FileVersionInfo.GetVersionInfo("Remotely_Agent.dll")?.FileVersion?.ToString()?.Trim();
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -14,5 +14,6 @@ namespace Remotely.Shared.Models
|
||||
public uint ID { get; internal set; }
|
||||
public string Name { get; internal set; }
|
||||
public SessionType Type { get; internal set; }
|
||||
public string Username { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
using Microsoft.Management.Infrastructure;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Shared.Services;
|
||||
using Remotely.Shared.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -11,6 +14,59 @@ namespace Remotely.Shared.Services
|
||||
{
|
||||
public class DeviceInformation
|
||||
{
|
||||
public static async Task<Device> Create(ConnectionInfo connectionInfo)
|
||||
{
|
||||
OSPlatform platform = OSUtils.GetPlatform();
|
||||
|
||||
var systemDrive = DriveInfo.GetDrives().FirstOrDefault(x =>
|
||||
x.IsReady &&
|
||||
x.RootDirectory.FullName.Contains(Path.GetPathRoot(Environment.SystemDirectory ?? Environment.CurrentDirectory)));
|
||||
|
||||
var device = new Device()
|
||||
{
|
||||
ID = connectionInfo.DeviceID,
|
||||
DeviceName = Environment.MachineName,
|
||||
Platform = platform.ToString(),
|
||||
ProcessorCount = Environment.ProcessorCount,
|
||||
OSArchitecture = RuntimeInformation.OSArchitecture,
|
||||
OSDescription = RuntimeInformation.OSDescription,
|
||||
Is64Bit = Environment.Is64BitOperatingSystem,
|
||||
IsOnline = true,
|
||||
Drives = DriveInfo.GetDrives().Where(x => x.IsReady).Select(x => new Drive()
|
||||
{
|
||||
DriveFormat = x.DriveFormat,
|
||||
DriveType = x.DriveType,
|
||||
Name = x.Name,
|
||||
RootDirectory = x.RootDirectory.FullName,
|
||||
FreeSpace = x.TotalSize > 0 ? x.TotalFreeSpace / x.TotalSize : 0,
|
||||
TotalSize = x.TotalSize > 0 ? Math.Round((double)(x.TotalSize / 1024 / 1024 / 1024), 2) : 0,
|
||||
VolumeLabel = x.VolumeLabel
|
||||
}).ToList(),
|
||||
OrganizationID = connectionInfo.OrganizationID,
|
||||
CurrentUser = DeviceInformation.GetCurrentUser()
|
||||
};
|
||||
|
||||
if (systemDrive != null && systemDrive.TotalSize > 0 && systemDrive.TotalFreeSpace > 0)
|
||||
{
|
||||
device.TotalStorage = Math.Round((double)(systemDrive.TotalSize / 1024 / 1024 / 1024), 2);
|
||||
device.UsedStorage = Math.Round((double)((systemDrive.TotalSize - systemDrive.TotalFreeSpace) / 1024 / 1024 / 1024), 2);
|
||||
}
|
||||
|
||||
|
||||
var (usedMemory, totalMemory) = DeviceInformation.GetMemoryInGB();
|
||||
device.UsedMemory = usedMemory;
|
||||
device.TotalMemory = totalMemory;
|
||||
|
||||
device.CpuUtilization = await DeviceInformation.GetCpuUtilization();
|
||||
|
||||
if (File.Exists("Remotely_Agent.dll"))
|
||||
{
|
||||
device.AgentVersion = FileVersionInfo.GetVersionInfo("Remotely_Agent.dll")?.FileVersion?.ToString()?.Trim();
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
public static async Task<double> GetCpuUtilization()
|
||||
{
|
||||
double totalUtilization = 0;
|
||||
@ -62,16 +118,12 @@ namespace Remotely.Shared.Services
|
||||
{
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
var session = CimSession.Create(null);
|
||||
var computerSystem = session.EnumerateInstances("root\\cimv2", "CIM_ComputerSystem");
|
||||
var username = computerSystem.FirstOrDefault().CimInstanceProperties["UserName"].Value ?? "";
|
||||
return username as string;
|
||||
return Win32Interop.GetActiveSessions().LastOrDefault()?.Username;
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
var users = OSUtils.StartProcessWithResults("users", "");
|
||||
var username = users?.Split()?.FirstOrDefault()?.Trim();
|
||||
return $"{Environment.UserDomainName}\\{username}";
|
||||
return users?.Split()?.FirstOrDefault()?.Trim();
|
||||
}
|
||||
throw new Exception("Unsupported operating system.");
|
||||
}
|
||||
@ -96,7 +148,6 @@ namespace Remotely.Shared.Services
|
||||
return (0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static (double, double) GetLinxMemoryInGB()
|
||||
{
|
||||
try
|
||||
@ -136,12 +187,15 @@ namespace Remotely.Shared.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
var session = CimSession.Create(null);
|
||||
var cimOS = session.EnumerateInstances("root\\cimv2", "CIM_OperatingSystem");
|
||||
var free = (ulong)(cimOS.FirstOrDefault()?.CimInstanceProperties["FreePhysicalMemory"]?.Value ?? 0);
|
||||
var freeGB = Math.Round(((double)free / 1024 / 1024), 2);
|
||||
var total = (ulong)(cimOS.FirstOrDefault()?.CimInstanceProperties["TotalVisibleMemorySize"]?.Value ?? 0);
|
||||
var totalGB = Math.Round(((double)total / 1024 / 1024), 2);
|
||||
var memoryStatus = new Kernel32.MEMORYSTATUSEX();
|
||||
double totalGB = 0;
|
||||
double freeGB = 0;
|
||||
|
||||
if (Kernel32.GlobalMemoryStatusEx(memoryStatus))
|
||||
{
|
||||
freeGB = Math.Round(((double)memoryStatus.ullAvailPhys / 1024 / 1024 / 1024), 2);
|
||||
totalGB = Math.Round(((double)memoryStatus.ullTotalPhys / 1024 / 1024 / 1024), 2);
|
||||
}
|
||||
|
||||
return (totalGB - freeGB, totalGB);
|
||||
}
|
||||
|
||||
@ -5,23 +5,82 @@ namespace Remotely.Shared.Win32
|
||||
{
|
||||
public static class Kernel32
|
||||
{
|
||||
#region DLL Imports
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hSnapshot);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetCommandLine();
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint WTSGetActiveConsoleSessionId();
|
||||
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
|
||||
public static extern uint WTSGetActiveConsoleSessionId();
|
||||
/// <summary>
|
||||
/// contains information about the current state of both physical and virtual memory, including extended memory
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public class MEMORYSTATUSEX
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
|
||||
/// </summary>
|
||||
public uint dwLength;
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetCommandLine();
|
||||
/// <summary>
|
||||
/// Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).
|
||||
/// </summary>
|
||||
public uint dwMemoryLoad;
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Total size of physical memory, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullTotalPhys;
|
||||
|
||||
/// <summary>
|
||||
/// Size of physical memory available, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullAvailPhys;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead.
|
||||
/// </summary>
|
||||
public ulong ullTotalPageFile;
|
||||
|
||||
/// <summary>
|
||||
/// Size of available memory to commit, in bytes. The limit is ullTotalPageFile.
|
||||
/// </summary>
|
||||
public ulong ullAvailPageFile;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the user mode portion of the virtual address space of the calling process, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullTotalVirtual;
|
||||
|
||||
/// <summary>
|
||||
/// Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullAvailVirtual;
|
||||
|
||||
/// <summary>
|
||||
/// Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes.
|
||||
/// </summary>
|
||||
public ulong ullAvailExtendedVirtual;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:MEMORYSTATUSEX"/> class.
|
||||
/// </summary>
|
||||
public MEMORYSTATUSEX()
|
||||
{
|
||||
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,14 +5,8 @@ namespace Remotely.Shared.Win32
|
||||
{
|
||||
public static class WTSAPI32
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WTS_SESSION_INFO
|
||||
{
|
||||
public uint SessionID;
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string pWinStationName;
|
||||
public WTS_CONNECTSTATE_CLASS State;
|
||||
}
|
||||
public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
|
||||
|
||||
public enum WTS_CONNECTSTATE_CLASS
|
||||
{
|
||||
WTSActive,
|
||||
@ -26,10 +20,36 @@ namespace Remotely.Shared.Win32
|
||||
WTSDown,
|
||||
WTSInit
|
||||
}
|
||||
public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
|
||||
|
||||
[DllImport("wtsapi32.dll", SetLastError = true)]
|
||||
static extern IntPtr WTSOpenServer(string pServerName);
|
||||
public enum WTS_INFO_CLASS
|
||||
{
|
||||
WTSInitialProgram,
|
||||
WTSApplicationName,
|
||||
WTSWorkingDirectory,
|
||||
WTSOEMId,
|
||||
WTSSessionId,
|
||||
WTSUserName,
|
||||
WTSWinStationName,
|
||||
WTSDomainName,
|
||||
WTSConnectState,
|
||||
WTSClientBuildNumber,
|
||||
WTSClientName,
|
||||
WTSClientDirectory,
|
||||
WTSClientProductId,
|
||||
WTSClientHardwareId,
|
||||
WTSClientAddress,
|
||||
WTSClientDisplay,
|
||||
WTSClientProtocolType,
|
||||
WTSIdleTime,
|
||||
WTSLogonTime,
|
||||
WTSIncomingBytes,
|
||||
WTSOutgoingBytes,
|
||||
WTSIncomingFrames,
|
||||
WTSOutgoingFrames,
|
||||
WTSClientInfo,
|
||||
WTSSessionInfo
|
||||
}
|
||||
|
||||
|
||||
[DllImport("wtsapi32.dll", SetLastError = true)]
|
||||
public static extern int WTSEnumerateSessions(
|
||||
@ -39,5 +59,22 @@ namespace Remotely.Shared.Win32
|
||||
ref System.IntPtr ppSessionInfo,
|
||||
ref int pCount);
|
||||
|
||||
[DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)]
|
||||
public static extern void WTSFreeMemory(IntPtr memory);
|
||||
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
public static extern bool WTSQuerySessionInformation(IntPtr hServer, uint sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned);
|
||||
|
||||
[DllImport("wtsapi32.dll", SetLastError = true)]
|
||||
static extern IntPtr WTSOpenServer(string pServerName);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WTS_SESSION_INFO
|
||||
{
|
||||
public uint SessionID;
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string pWinStationName;
|
||||
public WTS_CONNECTSTATE_CLASS State;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,8 @@ namespace Remotely.Shared.Win32
|
||||
{
|
||||
ID = consoleSessionId,
|
||||
Type = SessionType.Console,
|
||||
Name = "Console"
|
||||
Name = "Console",
|
||||
Username = GetUsernameFromSessionId(consoleSessionId)
|
||||
});
|
||||
|
||||
IntPtr ppSessionInfo = IntPtr.Zero;
|
||||
@ -43,7 +44,8 @@ namespace Remotely.Shared.Win32
|
||||
{
|
||||
ID = sessionInfo.SessionID,
|
||||
Name = sessionInfo.pWinStationName,
|
||||
Type = SessionType.RDP
|
||||
Type = SessionType.RDP,
|
||||
Username = GetUsernameFromSessionId(sessionInfo.SessionID)
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -79,11 +81,24 @@ namespace Remotely.Shared.Win32
|
||||
CloseDesktop(inputDesktop);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetUsernameFromSessionId(uint sessionId)
|
||||
{
|
||||
var username = string.Empty;
|
||||
|
||||
if (WTSAPI32.WTSQuerySessionInformation(IntPtr.Zero, sessionId, WTSAPI32.WTS_INFO_CLASS.WTSUserName, out var buffer, out var strLen) && strLen > 1)
|
||||
{
|
||||
username = Marshal.PtrToStringAnsi(buffer);
|
||||
WTSAPI32.WTSFreeMemory(buffer);
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
public static IntPtr OpenInputDesktop()
|
||||
{
|
||||
return User32.OpenInputDesktop(0, true, ACCESS_MASK.GENERIC_ALL);
|
||||
}
|
||||
|
||||
public static bool OpenInteractiveProcess(string applicationName, string desktopName, bool hiddenWindow, out PROCESS_INFORMATION procInfo)
|
||||
{
|
||||
uint winlogonPid = 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user