mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-19 07:01:35 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 99cfe5c8fb | |||
| 07385d0040 | |||
| c9000b1653 | |||
| 09bd0f6b5b | |||
| 6a90230dbb | |||
| ec70128239 | |||
| f2048bc3e5 | |||
| 9000c3bf2a | |||
| 3725f9b62f | |||
| 2c92e3e6f8 | |||
| f78271c2f5 | |||
| f2bdc19d74 | |||
| 0fde0eccba | |||
| 5c55fa97e7 | |||
| 323c7eb6c3 | |||
| 42dea46260 | |||
| 1bf65820c0 | |||
| ba1c5b6c8b | |||
| deb6c4eaa1 | |||
| af337a8fbd | |||
| 80d14c6c24 | |||
| 07d82be4c7 | |||
| 1e261f1125 | |||
| 8a1bde0773 | |||
| 617b99c39d | |||
| 8b4680fcee | |||
| e27ae2b202 |
@@ -8,10 +8,10 @@ assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
发布前请先尝试在 Issuse 内搜索一下你的问题是否已经被提出过,
|
||||
发布前请先尝试在 Issues 内搜索一下你的问题是否已经被提出过,
|
||||
详细地描述 bug,让大家都能理解,请一定确定你所要发布的内容是一个 Bug,如果不确定请发 Question
|
||||
别忘了填写标题,标题要简短的描述问题
|
||||
Before posting, please try searching in Issuse to see if your question has already been asked,
|
||||
Before posting, please try searching in Issues to see if your question has already been asked,
|
||||
Describe the bug in detail so that everyone can understand it
|
||||
Don't forget to fill in the title, which should briefly describe the problem
|
||||
-->
|
||||
|
||||
+12
-12
@@ -24,7 +24,7 @@
|
||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="3.1.27" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="3.1.27" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.27" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.AzureAppServices" Version="3.1.27" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="3.1.27" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.27" />
|
||||
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="3.1.27" />
|
||||
@@ -40,12 +40,12 @@
|
||||
<ItemGroup Condition=" $(TargetFramework.StartsWith('net6.0')) ">
|
||||
<!-- Entity Framework Plus -->
|
||||
<!-- A FREE & Open Source library to enhance EF6 and EF Core -->
|
||||
<PackageVersion Include="Z.EntityFramework.Plus.EFCore" Version="6.14.3" />
|
||||
<PackageVersion Include="Z.EntityFramework.Plus.EFCore" Version="6.14.4" />
|
||||
|
||||
<!-- AspNetCore 6 OpenId/OAuth -->
|
||||
<PackageVersion Include="AspNet.Security.OpenId.Steam" Version="6.0.0" />
|
||||
<PackageVersion Include="AspNet.Security.OAuth.QQ" Version="6.0.6" />
|
||||
<PackageVersion Include="AspNet.Security.OAuth.Apple" Version="6.0.6" />
|
||||
<PackageVersion Include="AspNet.Security.OAuth.QQ" Version="6.0.11" />
|
||||
<PackageVersion Include="AspNet.Security.OAuth.Apple" Version="6.0.11" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
@@ -74,7 +74,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- Microsoft.* -->
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<!--<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="1.4.1" />-->
|
||||
<!--<PackageVersion Include="Microsoft.Windows.SDK.NET.Ref" Version="10.0.19041.22" />-->
|
||||
<!--<PackageVersion Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />-->
|
||||
@@ -117,15 +117,15 @@
|
||||
<PackageVersion Include="Moq" Version="4.18.2" />
|
||||
|
||||
<!-- NLog -->
|
||||
<PackageVersion Include="NLog" Version="5.0.1" />
|
||||
<PackageVersion Include="NLog.Extensions.Logging" Version="5.0.1" />
|
||||
<PackageVersion Include="NLog.Web.AspNetCore" Version="5.1.0" />
|
||||
<PackageVersion Include="NLog" Version="5.0.4" />
|
||||
<PackageVersion Include="NLog.Extensions.Logging" Version="5.0.4" />
|
||||
<PackageVersion Include="NLog.Web.AspNetCore" Version="5.1.4" />
|
||||
<PackageVersion Include="AspNetCore2.NETStandard.NLog.Web.AspNetCore" Version="5.0.0" />
|
||||
|
||||
<!-- ReactiveUI -->
|
||||
<PackageVersion Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageVersion Include="Splat" Version="14.4.1" />
|
||||
<PackageVersion Include="DynamicData" Version="7.9.7" />
|
||||
<PackageVersion Include="DynamicData" Version="7.9.14" />
|
||||
<PackageVersion Include="ReactiveUI" Version="18.3.1" />
|
||||
<PackageVersion Include="ReactiveUI.Fody" Version="18.3.1" />
|
||||
<PackageVersion Include="ReactiveUI.XamForms" Version="18.3.1" />
|
||||
@@ -193,7 +193,7 @@
|
||||
<PackageVersion Include="NPOI" Version="2.5.6" />
|
||||
|
||||
<!-- Github API -->
|
||||
<PackageVersion Include="Octokit" Version="2.0.0" />
|
||||
<PackageVersion Include="Octokit" Version="2.0.1" />
|
||||
|
||||
<!-- ORM -->
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.8.116" />
|
||||
@@ -211,7 +211,7 @@
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
|
||||
<!-- Html Parser -->
|
||||
<PackageVersion Include="HtmlAgilityPack" Version="1.11.43" />
|
||||
<PackageVersion Include="HtmlAgilityPack" Version="1.11.45" />
|
||||
|
||||
<!-- Clipboard -->
|
||||
<PackageVersion Include="TextCopy" Version="6.1.0" />
|
||||
@@ -307,7 +307,7 @@
|
||||
|
||||
<!-- UWP -->
|
||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.1.3" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.1.4" />
|
||||
|
||||
<!-- Code Style -->
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.435" />
|
||||
|
||||
@@ -61,7 +61,7 @@ public sealed class FileSettingsProvider : ISerializationProvider
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
using var stream = new FileStream(_path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);
|
||||
using var stream = OpenReadWrite(_path);
|
||||
if (stream.Position > 0)
|
||||
{
|
||||
stream.Position = 0;
|
||||
@@ -72,6 +72,28 @@ public sealed class FileSettingsProvider : ISerializationProvider
|
||||
}
|
||||
}
|
||||
|
||||
static FileStream OpenReadWrite(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return OpenReadWrite();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
if (IOPath.FileTryDelete(path))
|
||||
{
|
||||
// 直接打开文件流失败,尝试删除后再打开一次
|
||||
return OpenReadWrite();
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
FileStream OpenReadWrite() => new(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
if (File.Exists(_path))
|
||||
|
||||
@@ -34,4 +34,23 @@ public static class ProcessExtensions
|
||||
process.Kill();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试 Process 组件在指定的毫秒数内等待关联进程退出。
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
/// <param name="milliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryWaitForExit(this Process process, int milliseconds = 9000)
|
||||
{
|
||||
try
|
||||
{
|
||||
return process.WaitForExit(milliseconds);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,11 @@ public static class FileEx
|
||||
public const string Qt = ".qt";
|
||||
public const string Wmv = ".wmv";
|
||||
|
||||
/// <summary>
|
||||
/// 导入注册条目 (.reg) 文件是 Regedit.exe 的功能,Regedt32.exe 不支持。您可以使用 Regedit.exe 对基于 Windows NT 4.0 或基于 Windows 2000 的计算机上注册表进行一些更改,但某些更改需要 Regedt32.exe。
|
||||
/// </summary>
|
||||
public const string Reg = ".reg";
|
||||
|
||||
public static readonly string[] ImageFileExtensions = new string[]
|
||||
{
|
||||
PNG,
|
||||
|
||||
@@ -153,6 +153,89 @@ public static class IOPath
|
||||
}
|
||||
}
|
||||
|
||||
static readonly object lock_GetCacheFilePath = new();
|
||||
|
||||
/// <summary>
|
||||
/// 根据缓存子文件夹名称与文件扩展名获取一个缓存文件路径
|
||||
/// </summary>
|
||||
/// <param name="dirName">缓存子文件夹名称</param>
|
||||
/// <param name="fileNamePrefix">文件名前缀</param>
|
||||
/// <param name="fileEx">文件扩展名</param>
|
||||
public static string GetCacheFilePath(string dirName, string fileNamePrefix, string fileEx)
|
||||
{
|
||||
lock (lock_GetCacheFilePath)
|
||||
{
|
||||
var cacheDirPath = Path.Combine(CacheDirectory, dirName);
|
||||
if (!Directory.Exists(cacheDirPath))
|
||||
{
|
||||
Directory.CreateDirectory(cacheDirPath);
|
||||
return GetCacheFilePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
string cacheFilePath;
|
||||
do
|
||||
{
|
||||
cacheFilePath = GetCacheFilePath();
|
||||
} while (File.Exists(cacheFilePath));
|
||||
return cacheFilePath;
|
||||
}
|
||||
|
||||
string GetCacheFilePath() => Path.Combine(cacheDirPath, GetCacheFileName());
|
||||
string GetCacheFileName() => $"{fileNamePrefix}_{DateTimeOffset.Now.Ticks}{Random2.GenerateRandomString(4)}{fileEx}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试延时一段时间后删除文件
|
||||
/// </summary>
|
||||
/// <param name="filePath">要删除的文件路径</param>
|
||||
/// <param name="millisecondsDelay">延时等待的毫秒数</param>
|
||||
public static async void TryDeleteInDelay(string filePath, int millisecondsDelay = 9000)
|
||||
{
|
||||
await Task.Delay(millisecondsDelay);
|
||||
FileTryDelete(filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动进程后尝试延时一段时间后删除文件
|
||||
/// </summary>
|
||||
/// <param name="process">启动的进程</param>
|
||||
/// <param name="filePath">要删除的文件路径</param>
|
||||
/// <param name="millisecondsDelay">延时等待的毫秒数</param>
|
||||
/// <param name="processWaitMillisecondsDelay">启动的进程等待退出的毫秒数</param>
|
||||
public static void TryDeleteInDelay(Process? process, string filePath, int millisecondsDelay = 9000, int processWaitMillisecondsDelay = 9000)
|
||||
{
|
||||
if (process != null)
|
||||
{
|
||||
var waitForExitResult = process.TryWaitForExit(processWaitMillisecondsDelay);
|
||||
if (!waitForExitResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
process.KillEntireProcessTree();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
TryDeleteInDelay(filePath, millisecondsDelay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FileTryDelete(filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试根据缓存子文件夹名称删除整个缓存子文件夹
|
||||
/// </summary>
|
||||
/// <param name="dirName">缓存子文件夹名称</param>
|
||||
public static void TryDeleteCacheSubDir(string dirName)
|
||||
{
|
||||
var cacheDirPath = Path.Combine(CacheDirectory, dirName);
|
||||
DirTryDelete(cacheDirPath);
|
||||
}
|
||||
|
||||
public abstract class FileSystemBase
|
||||
{
|
||||
protected FileSystemBase()
|
||||
|
||||
@@ -20,6 +20,27 @@ public sealed class ReverseProxyHttpClientHandler : DelegatingHandler
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送请求
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var uri = request.RequestUri;
|
||||
if (uri == null)
|
||||
{
|
||||
throw new ApplicationException("The requested URI must be specified.");
|
||||
}
|
||||
|
||||
// 设置请求头 host,修改协议为 http
|
||||
request.Headers.Host = uri.Host;
|
||||
request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
|
||||
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接回调
|
||||
/// </summary>
|
||||
|
||||
@@ -266,7 +266,7 @@ public abstract class CommandLineHost : IDisposable
|
||||
steamService.SetCurrentUser(account);
|
||||
}
|
||||
|
||||
steamService.StartSteam();
|
||||
steamService.StartSteamWithParameter();
|
||||
}
|
||||
});
|
||||
rootCommand.AddCommand(steamuser);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<Identity
|
||||
Name="4651ED44255E.47979655102CE"
|
||||
Publisher="CN=A90E406B-B2D3-4A23-B061-0FA1D65C4F66"
|
||||
Version="2.8.3.0" />
|
||||
Version="2.8.4.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Watt Toolkit</DisplayName>
|
||||
|
||||
+30
-1
@@ -31,11 +31,24 @@ namespace System.Application.Services.Implementation
|
||||
}
|
||||
|
||||
public async Task<byte[]> ProtectAsync(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await ProtectCoreAsync(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return await ProtectCore2Async(data);
|
||||
}
|
||||
}
|
||||
|
||||
static async Task<byte[]> ProtectCoreAsync(byte[] data)
|
||||
{
|
||||
// LOCAL=user and LOCAL=machine do not require enterprise auth capability
|
||||
var provider = GetDataProtectionProvider("LOCAL=user");
|
||||
|
||||
// https://appcenter.ms/orgs/BeyondDimension/apps/Steam/crashes/errors/842356268u/overview
|
||||
// https://appcenter.ms/orgs/BeyondDimension/apps/Steam/crashes/errors/1550045210u/overview
|
||||
// System.Runtime.InteropServices.COMException: 无法在设置线程模式后对其加以更改。 (0x80010106 (RPC_E_CHANGED_MODE))
|
||||
|
||||
var buffer = await provider.ProtectAsync(data.AsBuffer());
|
||||
@@ -45,7 +58,9 @@ namespace System.Application.Services.Implementation
|
||||
return encBytes;
|
||||
}
|
||||
|
||||
public async Task<byte[]> UnprotectAsync(byte[] data)
|
||||
static async Task<byte[]> ProtectCore2Async(byte[] data) => await await Task.Factory.StartNew(async () => await ProtectCoreAsync(data));
|
||||
|
||||
static async Task<byte[]> UnprotectCoreAsync(byte[] data)
|
||||
{
|
||||
var provider = GetDataProtectionProvider();
|
||||
|
||||
@@ -53,5 +68,19 @@ namespace System.Application.Services.Implementation
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
static async Task<byte[]> UnprotectCore2Async(byte[] data) => await await Task.Factory.StartNew(async () => await UnprotectCoreAsync(data));
|
||||
|
||||
public async Task<byte[]> UnprotectAsync(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await UnprotectCoreAsync(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return await UnprotectCore2Async(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -2,6 +2,11 @@ namespace System.Application.Services.Implementation
|
||||
{
|
||||
partial class WindowsPlatformServiceImpl : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于 <see cref="IOPath.GetCacheFilePath(string, string, string)"/> 中 dirName,临时文件夹名称,在程序退出时将删除整个文件夹
|
||||
/// </summary>
|
||||
const string CacheTempDirName = "Temporary";
|
||||
|
||||
bool disposedValue;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
@@ -12,6 +17,8 @@ namespace System.Application.Services.Implementation
|
||||
{
|
||||
// TODO: 释放托管状态(托管对象)
|
||||
isLightOrDarkThemeWatch?.Dispose();
|
||||
|
||||
IOPath.TryDeleteCacheSubDir(CacheTempDirName);
|
||||
}
|
||||
|
||||
// TODO: 释放未托管的资源(未托管的对象)并重写终结器
|
||||
|
||||
+341
-331
@@ -1,6 +1,5 @@
|
||||
using Microsoft.Win32;
|
||||
using System.Application.Models;
|
||||
using System.Application.UI;
|
||||
using System.Application.UI.Resx;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -11,343 +10,354 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using Windows.ApplicationModel;
|
||||
using System.Application.Properties;
|
||||
using System.Text;
|
||||
using _SR = System.Application.Properties.SR;
|
||||
|
||||
namespace System.Application.Services.Implementation
|
||||
namespace System.Application.Services.Implementation;
|
||||
|
||||
internal sealed partial class WindowsPlatformServiceImpl : IPlatformService
|
||||
{
|
||||
internal sealed partial class WindowsPlatformServiceImpl : IPlatformService
|
||||
const string TAG = "WindowsPlatformS";
|
||||
const string SteamRegistryPath = @"SOFTWARE\Valve\Steam";
|
||||
|
||||
public string? GetRegistryVdfPath() { return null; }
|
||||
|
||||
public string GetCommandLineArgs(Process process)
|
||||
{
|
||||
const string TAG = "WindowsPlatformS";
|
||||
const string SteamRegistryPath = @"SOFTWARE\Valve\Steam";
|
||||
|
||||
public string? GetRegistryVdfPath() { return null; }
|
||||
|
||||
public string GetCommandLineArgs(Process process)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
using var searcher = new ManagementObjectSearcher(
|
||||
"SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id);
|
||||
using var objects = searcher.Get();
|
||||
var @object = objects.Cast<ManagementBaseObject>().SingleOrDefault();
|
||||
return @object?["CommandLine"]?.ToString() ?? "";
|
||||
}
|
||||
catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005)
|
||||
{
|
||||
// 没有对该进程的安全访问权限。
|
||||
return string.Empty;
|
||||
}
|
||||
using var searcher = new ManagementObjectSearcher(
|
||||
"SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id);
|
||||
using var objects = searcher.Get();
|
||||
var @object = objects.Cast<ManagementBaseObject>().SingleOrDefault();
|
||||
return @object?["CommandLine"]?.ToString() ?? "";
|
||||
}
|
||||
|
||||
static readonly Lazy<string> mHostsFilePath = new(() =>
|
||||
catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005)
|
||||
{
|
||||
return Path.Combine(Environment.SystemDirectory, "drivers", "etc", "hosts");
|
||||
});
|
||||
|
||||
public string HostsFilePath => mHostsFilePath.Value;
|
||||
|
||||
public string DefaultHostsContent => _SR.hosts;
|
||||
|
||||
static string GetFolderPath(Environment.SpecialFolder folder)
|
||||
{
|
||||
switch (folder)
|
||||
{
|
||||
case Environment.SpecialFolder.ProgramFiles:
|
||||
var trimEndMark = " (x86)";
|
||||
var value = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||||
if (value.EndsWith(trimEndMark, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var value2 = value.Substring(0, value.Length - trimEndMark.Length);
|
||||
if (Directory.Exists(value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
default:
|
||||
return Environment.GetFolderPath(folder);
|
||||
}
|
||||
// 没有对该进程的安全访问权限。
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public void OpenFolderByDirectoryPath(DirectoryInfo info)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = Explorer,
|
||||
Arguments = $"\"{info.FullName}\"",
|
||||
UseShellExecute = false,
|
||||
});
|
||||
}
|
||||
|
||||
public void OpenFolderSelectFilePath(FileInfo info)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = Explorer,
|
||||
Arguments = $"/select,\"{info.FullName}\"",
|
||||
UseShellExecute = false,
|
||||
});
|
||||
}
|
||||
|
||||
public string? GetFileName(TextReaderProvider provider)
|
||||
{
|
||||
switch (provider)
|
||||
{
|
||||
case TextReaderProvider.VSCode:
|
||||
var vsCodePaths = new[] {
|
||||
GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
|
||||
}.Distinct().Select(x => Path.Combine(x, "Microsoft VS Code", "Code.exe"));
|
||||
|
||||
foreach (var vsCodePath in vsCodePaths)
|
||||
{
|
||||
if (File.Exists(vsCodePath))
|
||||
{
|
||||
return vsCodePath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
case TextReaderProvider.Notepad:
|
||||
return "notepad";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSystemSessionEnding(Action action)
|
||||
{
|
||||
SystemEvents.SessionEnding += (sender, e) =>
|
||||
{
|
||||
//IDesktopAppService.Instance.CompositeDisposable.Dispose();
|
||||
action.Invoke();
|
||||
};
|
||||
}
|
||||
|
||||
static string? GetFullPath(string s)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(s))
|
||||
{
|
||||
return Path.GetFullPath(s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string? GetSteamDirPath()
|
||||
=> GetFullPath(Registry.CurrentUser.Read(SteamRegistryPath, "SteamPath"));
|
||||
|
||||
public string? GetSteamProgramPath()
|
||||
=> GetFullPath(Registry.CurrentUser.Read(SteamRegistryPath, "SteamExe"));
|
||||
|
||||
public string GetLastSteamLoginUserName()
|
||||
=> Registry.CurrentUser.Read(SteamRegistryPath, "AutoLoginUser");
|
||||
|
||||
public void SetCurrentUser(string userName)
|
||||
{
|
||||
if (DesktopBridge.IsRunningAsUwp)
|
||||
{
|
||||
var reg = $"Windows Registry Editor Version 5.00{Environment.NewLine}[HKEY_CURRENT_USER\\Software\\Valve\\Steam]{Environment.NewLine}\"AutoLoginUser\"=\"{userName}\"";
|
||||
var path = Path.Combine(IOPath.CacheDirectory, "switchuser.reg");
|
||||
File.WriteAllText(path, reg, Text.Encoding.UTF8);
|
||||
var p = Process2.Start("regedit", $"/s \"{path}\"", true);
|
||||
p?.WaitForExit();
|
||||
}
|
||||
else
|
||||
{
|
||||
Registry.CurrentUser.AddOrUpdate(SteamRegistryPath, "AutoLoginUser", userName, RegistryValueKind.String);
|
||||
}
|
||||
}
|
||||
|
||||
static string GetMachineSecretKey()
|
||||
=> Registry.LocalMachine.Read(@"SOFTWARE\Microsoft\Cryptography", "MachineGuid");
|
||||
|
||||
static readonly Lazy<(byte[] key, byte[] iv)> mMachineSecretKey = IPlatformService.GetMachineSecretKey(GetMachineSecretKey);
|
||||
|
||||
public (byte[] key, byte[] iv) MachineSecretKey => mMachineSecretKey.Value;
|
||||
|
||||
//const string runas_exe = "runas.exe";
|
||||
//static Process? StartAsInvokerByRunas(string fileName, string? arguments = null)
|
||||
//{
|
||||
// // https://blog.lindexi.com/post/%E5%A6%82%E4%BD%95%E5%9C%A8-RunAs-%E5%90%AF%E5%8A%A8%E7%9A%84%E8%BD%AF%E4%BB%B6%E4%BC%A0%E5%85%A5%E5%B8%A6%E7%A9%BA%E6%A0%BC%E7%9A%84%E8%B7%AF%E5%BE%84%E5%B8%A6%E7%A9%BA%E6%A0%BC%E5%8F%82%E6%95%B0.html
|
||||
// string arguments_;
|
||||
// if (string.IsNullOrEmpty(arguments))
|
||||
// arguments_ = $"/trustlevel:0x20000 \"{fileName}\"";
|
||||
// else arguments_ = $"/trustlevel:0x20000 \"{fileName} \"{arguments}\"\"";
|
||||
// return Process.Start(runas_exe, arguments_);
|
||||
//}
|
||||
|
||||
static readonly Lazy<string> _explorer_exe = new(() => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe"));
|
||||
|
||||
/// <summary>
|
||||
/// %windir%\explorer.exe
|
||||
/// </summary>
|
||||
static string Explorer => _explorer_exe.Value;
|
||||
|
||||
static Process? StartAsInvokerByExplorer(string fileName, string? arguments = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
return Process.Start(Explorer, $"\"{fileName}\"");
|
||||
var cacheCmdFile = Path.Combine(IOPath.CacheDirectory, "StartAsInvokerByExplorer" + FileEx.CMD);
|
||||
if (File.Exists(cacheCmdFile)) File.Delete(cacheCmdFile);
|
||||
File.WriteAllText(cacheCmdFile, $"@echo {Constants.HARDCODED_APP_NAME} StartAsInvokerByExplorer{Environment.NewLine}start \"\" \"{fileName}\" {arguments}{Environment.NewLine}exit 0");
|
||||
return Process.Start(Explorer, $"\"{cacheCmdFile}\"");
|
||||
}
|
||||
|
||||
public Process? StartAsInvoker(string fileName, string? arguments = null)
|
||||
{
|
||||
if (((IPlatformService)this).IsAdministrator)
|
||||
{
|
||||
// runas /trustlevel:0x20000 没有真正的降权,只是作为具有限制特权,使用 explorer 最好,但不接受参数,可以创建一个临时cmd脚本启动
|
||||
//return StartAsInvokerByRunas(fileName, arguments);
|
||||
return StartAsInvokerByExplorer(fileName, arguments);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return Process2.Start(fileName, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
//public Process? StartAsInvoker(ProcessStartInfo startInfo)
|
||||
//{
|
||||
// startInfo.FileName = runas_exe;
|
||||
// startInfo.Arguments = $"/trustlevel:0x20000 \"{startInfo.FileName}\"";
|
||||
// return Process.Start(startInfo);
|
||||
//}
|
||||
|
||||
//public Process? GetProcessByPortOccupy(ushort port, bool isTCPorUDP = true)
|
||||
//{
|
||||
// if (isTCPorUDP)
|
||||
// {
|
||||
// return SocketHelper.GetProcessByTcpPort(port);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new NotSupportedException();
|
||||
// }
|
||||
// //try
|
||||
// //{
|
||||
// // using var p = new Process
|
||||
// // {
|
||||
// // StartInfo = new ProcessStartInfo
|
||||
// // {
|
||||
// // FileName = "cmd",
|
||||
// // UseShellExecute = false,
|
||||
// // RedirectStandardInput = true,
|
||||
// // RedirectStandardOutput = true,
|
||||
// // CreateNoWindow = true,
|
||||
// // },
|
||||
// // };
|
||||
// // p.Start();
|
||||
// // p.StandardInput.WriteLine($"netstat -ano|findstr \"{port}\"&exit");
|
||||
// // p.StandardInput.AutoFlush = true;
|
||||
// // var reader = p.StandardOutput;
|
||||
// // while (!reader.EndOfStream)
|
||||
// // {
|
||||
// // var line = reader.ReadLine();
|
||||
// // if (line == null) break;
|
||||
// // var lineArray = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
// // if (lineArray.Length != 5) continue;
|
||||
// // if (!lineArray[0].Equals(isTCPorUDP ? "TCP" : "UDP", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
// // if (!lineArray[3].Equals("LISTENING", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
// // if (!lineArray[1].EndsWith($":{port}")) continue;
|
||||
// // if (!ushort.TryParse(lineArray[4], out var pid)) continue;
|
||||
// // p.Close();
|
||||
// // return Process.GetProcessById(pid);
|
||||
// // }
|
||||
// // _ = p.WaitForExit(550);
|
||||
// //}
|
||||
// //catch
|
||||
// //{
|
||||
// //}
|
||||
// //return default;
|
||||
//}
|
||||
|
||||
const string ProxyOverride = "\"ProxyOverride\"=\"localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*\"";
|
||||
|
||||
/// <summary>
|
||||
/// 设置启用或关闭系统代理
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="ip"></param>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public bool SetAsSystemProxy(bool state, IPAddress? ip, int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
var proxyEnable = $"\"ProxyEnable\"=dword:{(state ? "00000001" : "00000000")}";
|
||||
var hasIpAndProt = ip != null && port >= 0;
|
||||
var proxyServer = hasIpAndProt ? $"\"proxyServer\"=\"{ip}:{port}\"" : "";
|
||||
var reg = $"Windows Registry Editor Version 5.00{Environment.NewLine}[HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings]{Environment.NewLine}{proxyEnable}{Environment.NewLine}{(state ? $"{ProxyOverride}{Environment.NewLine}" : "")}{proxyServer}";
|
||||
var path = Path.Combine(IOPath.CacheDirectory, "switchproxy.reg");
|
||||
File.WriteAllText(path, reg, Text.Encoding.UTF8);
|
||||
var p = Process2.Start("regedit", $"/s \"{path}\"", true);
|
||||
p?.WaitForExit();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Toast.LogAndShowT(ex, TAG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置启用或关闭PAC代理
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public bool SetAsSystemPACProxy(bool state, string? url = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var regAutoConfigUrl = state ? $"\"AutoConfigURL\"=\"{url}\"" : "\"AutoConfigURL\"=\"\"";
|
||||
var reg = $"Windows Registry Editor Version 5.00{Environment.NewLine}[HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings]{Environment.NewLine}{regAutoConfigUrl}";
|
||||
var path = Path.Combine(IOPath.CacheDirectory, "switchpacproxy.reg");
|
||||
File.WriteAllText(path, reg, Text.Encoding.UTF8);
|
||||
var p = Process2.Start("regedit", $"/s \"{path}\"", true);
|
||||
p?.WaitForExit();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Toast.LogAndShowT(ex, TAG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<KeyValuePair<string, string>> GetFontsByGdiPlus()
|
||||
{
|
||||
// https://docs.microsoft.com/zh-cn/typography/font-list
|
||||
var culture = R.Culture;
|
||||
InstalledFontCollection ifc = new();
|
||||
var list = ifc.Families.Where(x => x.IsStyleAvailable(FontStyle.Regular)).Select(x => KeyValuePair.Create(x.GetName(culture.LCID), x.GetName(1033))).ToList();
|
||||
list.Insert(0, IFontManager.Default);
|
||||
return list;
|
||||
}
|
||||
|
||||
#region IsInstall
|
||||
|
||||
static readonly Lazy<bool> _IsInstall = new(() =>
|
||||
{
|
||||
using var reg32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
|
||||
var value = reg32.Read(@"SOFTWARE\Steam++", "InstPath").TrimEnd(Path.DirectorySeparatorChar);
|
||||
return string.Equals(IOPath.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar), value, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
/// <inheritdoc cref="IPlatformService.IsInstall"/>
|
||||
public static bool IsInstall => _IsInstall.Value;
|
||||
|
||||
bool IPlatformService.IsInstall => IsInstall;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
static readonly Lazy<string> mHostsFilePath = new(() =>
|
||||
{
|
||||
return Path.Combine(Environment.SystemDirectory, "drivers", "etc", "hosts");
|
||||
});
|
||||
|
||||
public string HostsFilePath => mHostsFilePath.Value;
|
||||
|
||||
public string DefaultHostsContent => _SR.hosts;
|
||||
|
||||
static string GetFolderPath(Environment.SpecialFolder folder)
|
||||
{
|
||||
switch (folder)
|
||||
{
|
||||
case Environment.SpecialFolder.ProgramFiles:
|
||||
var trimEndMark = " (x86)";
|
||||
var value = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||||
if (value.EndsWith(trimEndMark, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var value2 = value[..^trimEndMark.Length];
|
||||
if (Directory.Exists(value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
default:
|
||||
return Environment.GetFolderPath(folder);
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenFolderByDirectoryPath(DirectoryInfo info)
|
||||
{
|
||||
StartProcessExplorer($"\"{info.FullName}\"");
|
||||
}
|
||||
|
||||
public void OpenFolderSelectFilePath(FileInfo info)
|
||||
{
|
||||
StartProcessExplorer($"/select,\"{info.FullName}\"");
|
||||
}
|
||||
|
||||
public string? GetFileName(TextReaderProvider provider)
|
||||
{
|
||||
switch (provider)
|
||||
{
|
||||
case TextReaderProvider.VSCode:
|
||||
var vsCodePaths = new[] {
|
||||
GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
|
||||
}.Distinct().Select(x => Path.Combine(x, "Microsoft VS Code", "Code.exe"));
|
||||
|
||||
foreach (var vsCodePath in vsCodePaths)
|
||||
{
|
||||
if (File.Exists(vsCodePath))
|
||||
{
|
||||
return vsCodePath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
case TextReaderProvider.Notepad:
|
||||
return "notepad";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSystemSessionEnding(Action action)
|
||||
{
|
||||
SystemEvents.SessionEnding += (sender, e) =>
|
||||
{
|
||||
//IDesktopAppService.Instance.CompositeDisposable.Dispose();
|
||||
action.Invoke();
|
||||
};
|
||||
}
|
||||
|
||||
static string? GetFullPath(string s)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(s))
|
||||
{
|
||||
return Path.GetFullPath(s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string? GetSteamDirPath()
|
||||
=> GetFullPath(Registry.CurrentUser.Read(SteamRegistryPath, "SteamPath"));
|
||||
|
||||
public string? GetSteamProgramPath()
|
||||
=> GetFullPath(Registry.CurrentUser.Read(SteamRegistryPath, "SteamExe"));
|
||||
|
||||
public string GetLastSteamLoginUserName()
|
||||
=> Registry.CurrentUser.Read(SteamRegistryPath, "AutoLoginUser");
|
||||
|
||||
public void SetCurrentUser(string userName)
|
||||
{
|
||||
if (DesktopBridge.IsRunningAsUwp)
|
||||
{
|
||||
var reg = $"Windows Registry Editor Version 5.00{Environment.NewLine}[HKEY_CURRENT_USER\\Software\\Valve\\Steam]{Environment.NewLine}\"AutoLoginUser\"=\"{userName}\"";
|
||||
var path = IOPath.GetCacheFilePath(CacheTempDirName, "SwitchSteamUser", FileEx.Reg);
|
||||
File.WriteAllText(path, reg, Encoding.UTF8);
|
||||
var p = StartProcessRegedit($"/s \"{path}\"");
|
||||
IOPath.TryDeleteInDelay(p, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Registry.CurrentUser.AddOrUpdate(SteamRegistryPath, "AutoLoginUser", userName, RegistryValueKind.String);
|
||||
}
|
||||
}
|
||||
|
||||
static string GetMachineSecretKey()
|
||||
=> Registry.LocalMachine.Read(@"SOFTWARE\Microsoft\Cryptography", "MachineGuid");
|
||||
|
||||
static readonly Lazy<(byte[] key, byte[] iv)> mMachineSecretKey = IPlatformService.GetMachineSecretKey(GetMachineSecretKey);
|
||||
|
||||
public (byte[] key, byte[] iv) MachineSecretKey => mMachineSecretKey.Value;
|
||||
|
||||
/// <summary>
|
||||
/// %windir%
|
||||
/// </summary>
|
||||
static readonly Lazy<string> _windir = new(() => Environment.GetFolderPath(Environment.SpecialFolder.Windows));
|
||||
|
||||
//const string runas_exe = "runas.exe";
|
||||
//static Process? StartAsInvokerByRunas(string fileName, string? arguments = null)
|
||||
//{
|
||||
// // https://blog.lindexi.com/post/%E5%A6%82%E4%BD%95%E5%9C%A8-RunAs-%E5%90%AF%E5%8A%A8%E7%9A%84%E8%BD%AF%E4%BB%B6%E4%BC%A0%E5%85%A5%E5%B8%A6%E7%A9%BA%E6%A0%BC%E7%9A%84%E8%B7%AF%E5%BE%84%E5%B8%A6%E7%A9%BA%E6%A0%BC%E5%8F%82%E6%95%B0.html
|
||||
// string arguments_;
|
||||
// if (string.IsNullOrEmpty(arguments))
|
||||
// arguments_ = $"/trustlevel:0x20000 \"{fileName}\"";
|
||||
// else arguments_ = $"/trustlevel:0x20000 \"{fileName} \"{arguments}\"\"";
|
||||
// return Process.Start(runas_exe, arguments_);
|
||||
//}
|
||||
|
||||
static readonly Lazy<string> _explorer_exe = new(() => Path.Combine(_windir.Value, "explorer.exe"));
|
||||
|
||||
/// <summary>
|
||||
/// %windir%\explorer.exe
|
||||
/// </summary>
|
||||
static string Explorer => _explorer_exe.Value;
|
||||
|
||||
/// <summary>
|
||||
/// 带参数(可选/null)启动 %windir%\explorer.exe
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
static Process? StartProcessExplorer(string args) => Process2.Start(Explorer, args, workingDirectory: _windir.Value);
|
||||
|
||||
static readonly Lazy<string> _regedit_exe = new(() => Path.Combine(_windir.Value, "regedit.exe"));
|
||||
|
||||
/// <summary>
|
||||
/// %windir%\regedit.exe
|
||||
/// </summary>
|
||||
static string Regedit => _regedit_exe.Value;
|
||||
|
||||
/// <summary>
|
||||
/// 带参数(可选/null)启动 %windir%\regedit.exe
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
static Process? StartProcessRegedit(string? args) => Process2.Start(Regedit, args, workingDirectory: _windir.Value);
|
||||
|
||||
static Process? StartAsInvokerByExplorer(string fileName, string? arguments = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
return StartProcessExplorer($"\"{fileName}\"");
|
||||
var cacheCmdFile = IOPath.GetCacheFilePath(CacheTempDirName, "StartAsInvokerByExplorer", FileEx.CMD);
|
||||
File.WriteAllText(cacheCmdFile, $"@echo {Constants.HARDCODED_APP_NAME} StartAsInvokerByExplorer{Environment.NewLine}start \"\" \"{fileName}\" {arguments}{Environment.NewLine}exit 0");
|
||||
var process = StartProcessExplorer($"\"{cacheCmdFile}\"");
|
||||
IOPath.TryDeleteInDelay(process, cacheCmdFile);
|
||||
return process;
|
||||
}
|
||||
|
||||
public Process? StartAsInvoker(string fileName, string? arguments = null)
|
||||
{
|
||||
if (((IPlatformService)this).IsAdministrator)
|
||||
{
|
||||
// runas /trustlevel:0x20000 没有真正的降权,只是作为具有限制特权,使用 explorer 最好,但不接受参数,可以创建一个临时cmd脚本启动
|
||||
//return StartAsInvokerByRunas(fileName, arguments);
|
||||
return StartAsInvokerByExplorer(fileName, arguments);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return Process2.Start(fileName, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
//public Process? StartAsInvoker(ProcessStartInfo startInfo)
|
||||
//{
|
||||
// startInfo.FileName = runas_exe;
|
||||
// startInfo.Arguments = $"/trustlevel:0x20000 \"{startInfo.FileName}\"";
|
||||
// return Process.Start(startInfo);
|
||||
//}
|
||||
|
||||
//public Process? GetProcessByPortOccupy(ushort port, bool isTCPorUDP = true)
|
||||
//{
|
||||
// if (isTCPorUDP)
|
||||
// {
|
||||
// return SocketHelper.GetProcessByTcpPort(port);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new NotSupportedException();
|
||||
// }
|
||||
// //try
|
||||
// //{
|
||||
// // using var p = new Process
|
||||
// // {
|
||||
// // StartInfo = new ProcessStartInfo
|
||||
// // {
|
||||
// // FileName = "cmd",
|
||||
// // UseShellExecute = false,
|
||||
// // RedirectStandardInput = true,
|
||||
// // RedirectStandardOutput = true,
|
||||
// // CreateNoWindow = true,
|
||||
// // },
|
||||
// // };
|
||||
// // p.Start();
|
||||
// // p.StandardInput.WriteLine($"netstat -ano|findstr \"{port}\"&exit");
|
||||
// // p.StandardInput.AutoFlush = true;
|
||||
// // var reader = p.StandardOutput;
|
||||
// // while (!reader.EndOfStream)
|
||||
// // {
|
||||
// // var line = reader.ReadLine();
|
||||
// // if (line == null) break;
|
||||
// // var lineArray = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
// // if (lineArray.Length != 5) continue;
|
||||
// // if (!lineArray[0].Equals(isTCPorUDP ? "TCP" : "UDP", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
// // if (!lineArray[3].Equals("LISTENING", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
// // if (!lineArray[1].EndsWith($":{port}")) continue;
|
||||
// // if (!ushort.TryParse(lineArray[4], out var pid)) continue;
|
||||
// // p.Close();
|
||||
// // return Process.GetProcessById(pid);
|
||||
// // }
|
||||
// // _ = p.WaitForExit(550);
|
||||
// //}
|
||||
// //catch
|
||||
// //{
|
||||
// //}
|
||||
// //return default;
|
||||
//}
|
||||
|
||||
const string ProxyOverride = "\"ProxyOverride\"=\"localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*\"";
|
||||
|
||||
/// <summary>
|
||||
/// 设置启用或关闭系统代理
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="ip"></param>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public bool SetAsSystemProxy(bool state, IPAddress? ip, int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
var proxyEnable = $"\"ProxyEnable\"=dword:{(state ? "00000001" : "00000000")}";
|
||||
var hasIpAndProt = ip != null && port >= 0;
|
||||
var proxyServer = hasIpAndProt ? $"\"proxyServer\"=\"{ip}:{port}\"" : "";
|
||||
var reg = $"Windows Registry Editor Version 5.00{Environment.NewLine}[HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings]{Environment.NewLine}{proxyEnable}{Environment.NewLine}{(state ? $"{ProxyOverride}{Environment.NewLine}" : "")}{proxyServer}";
|
||||
var path = IOPath.GetCacheFilePath(CacheTempDirName, "SwitchProxy", FileEx.Reg);
|
||||
File.WriteAllText(path, reg, Encoding.UTF8);
|
||||
var p = StartProcessRegedit($"/s \"{path}\"");
|
||||
IOPath.TryDeleteInDelay(p, path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Toast.LogAndShowT(ex, TAG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置启用或关闭PAC代理
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public bool SetAsSystemPACProxy(bool state, string? url = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var regAutoConfigUrl = state ? $"\"AutoConfigURL\"=\"{url}\"" : "\"AutoConfigURL\"=\"\"";
|
||||
var reg = $"Windows Registry Editor Version 5.00{Environment.NewLine}[HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings]{Environment.NewLine}{regAutoConfigUrl}";
|
||||
var path = IOPath.GetCacheFilePath(CacheTempDirName, "SwitchPacProxy", FileEx.Reg);
|
||||
File.WriteAllText(path, reg, Encoding.UTF8);
|
||||
var p = StartProcessRegedit($"/s \"{path}\"");
|
||||
IOPath.TryDeleteInDelay(p, path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Toast.LogAndShowT(ex, TAG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<KeyValuePair<string, string>> GetFontsByGdiPlus()
|
||||
{
|
||||
// https://docs.microsoft.com/zh-cn/typography/font-list
|
||||
var culture = R.Culture;
|
||||
InstalledFontCollection ifc = new();
|
||||
var list = ifc.Families.Where(x => x.IsStyleAvailable(FontStyle.Regular)).Select(x => KeyValuePair.Create(x.GetName(culture.LCID), x.GetName(1033))).ToList();
|
||||
list.Insert(0, IFontManager.Default);
|
||||
return list;
|
||||
}
|
||||
|
||||
#region IsInstall
|
||||
|
||||
static readonly Lazy<bool> _IsInstall = new(() =>
|
||||
{
|
||||
using var reg32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
|
||||
var value = reg32.Read(@"SOFTWARE\Steam++", "InstPath").TrimEnd(Path.DirectorySeparatorChar);
|
||||
return string.Equals(IOPath.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar), value, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
/// <inheritdoc cref="IPlatformService.IsInstall"/>
|
||||
public static bool IsInstall => _IsInstall.Value;
|
||||
|
||||
bool IPlatformService.IsInstall => IsInstall;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Application.Models;
|
||||
using System.Application.Settings;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -55,6 +56,11 @@ namespace System.Application.Services
|
||||
/// <param name="arguments"></param>
|
||||
void StartSteam(string? arguments = null);
|
||||
|
||||
/// <summary>
|
||||
/// 使用配置的参数启动 Steam
|
||||
/// </summary>
|
||||
void StartSteamWithParameter() => StartSteam(SteamSettings.SteamStratParameter.Value);
|
||||
|
||||
/// <summary>
|
||||
/// 安全退出 Steam(如果有修改Steam数据的操作请退出后在执行不然Steam安全退出会还原修改)
|
||||
/// </summary>
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace System.Application.Services
|
||||
public void Initialize()
|
||||
{
|
||||
if (!stmService.IsRunningSteamProcess && SteamSettings.IsAutoRunSteam.Value)
|
||||
stmService.StartSteam(SteamSettings.SteamStratParameter.Value);
|
||||
stmService.StartSteamWithParameter();
|
||||
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace System.Application.UI.ViewModels
|
||||
steamService.SetCurrentUser(string.Empty);
|
||||
}
|
||||
|
||||
steamService.StartSteam(SteamSettings.SteamStratParameter.Value);
|
||||
steamService.StartSteamWithParameter();
|
||||
}
|
||||
|
||||
public async void DeleteUserButton_Click(SteamUser user)
|
||||
|
||||
@@ -47,12 +47,13 @@ namespace System.Application.UI.ViewModels
|
||||
|
||||
public async Task SaveSteamEditedApps()
|
||||
{
|
||||
if (await ISteamService.Instance.SaveAppInfosToSteam())
|
||||
var stmService = ISteamService.Instance;
|
||||
if (await stmService.SaveAppInfosToSteam())
|
||||
{
|
||||
if (await MessageBox.ShowAsync(AppResources.SaveEditedAppInfo_RestartSteamTip, ThisAssembly.AssemblyTrademark, MessageBox.Button.OKCancel) == MessageBox.Result.OK)
|
||||
{
|
||||
await ISteamService.Instance.ShutdownSteamAsync();
|
||||
ISteamService.Instance.StartSteam();
|
||||
await stmService.ShutdownSteamAsync();
|
||||
stmService.StartSteamWithParameter();
|
||||
}
|
||||
Toast.Show(AppResources.SaveEditedAppInfo_SaveToSteamSuccess);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace System.Application.UI.ViewModels
|
||||
var index = item.Index;
|
||||
if (up ? item.Index != 0 : item.Index != _AuthorizedSourceList.Count - 1)
|
||||
{
|
||||
var dest = AuthorizedList[(up ? index - 1 : index + 1)];
|
||||
var dest = AuthorizedList[up ? index - 1 : index + 1];
|
||||
|
||||
item.Index = dest.Index;
|
||||
dest.Index = index;
|
||||
@@ -198,7 +198,7 @@ namespace System.Application.UI.ViewModels
|
||||
if (result.IsOK())
|
||||
{
|
||||
steamService.TryKillSteamProcess();
|
||||
steamService.StartSteam();
|
||||
steamService.StartSteamWithParameter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
using NUnit.Framework;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
#if WINDOWS
|
||||
using Windows.Security.Cryptography.DataProtection;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Runtime.Versioning;
|
||||
#endif
|
||||
|
||||
namespace System;
|
||||
|
||||
@@ -81,4 +87,67 @@ public class ByteArrayTest
|
||||
|
||||
Assert.IsTrue(value1 == value3);
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
/// <summary>
|
||||
/// Windows10DataProtectionProvider 的单元测试
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Test]
|
||||
public async Task DataProtection()
|
||||
{
|
||||
if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 10240)) return;
|
||||
|
||||
var value = DateTime.Now.ToString() + " 🔮🎮";
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
|
||||
var e = await ProtectCore2Async(bytes);
|
||||
var d = await UnprotectCore2Async(e);
|
||||
|
||||
TestContext.WriteLine(Encoding.UTF8.GetString(d));
|
||||
|
||||
Assert.IsTrue(d.SequenceEqual(bytes));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WINDOWS
|
||||
[SupportedOSPlatform("Windows10.0.10240.0")]
|
||||
static DataProtectionProvider GetDataProtectionProvider(string? protectionDescriptor = null)
|
||||
{
|
||||
DataProtectionProvider provider = protectionDescriptor == null ? new() : new(protectionDescriptor);
|
||||
return provider;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("Windows10.0.10240.0")]
|
||||
static async Task<byte[]> ProtectCoreAsync(byte[] data)
|
||||
{
|
||||
// LOCAL=user and LOCAL=machine do not require enterprise auth capability
|
||||
var provider = GetDataProtectionProvider("LOCAL=user");
|
||||
|
||||
// https://appcenter.ms/orgs/BeyondDimension/apps/Steam/crashes/errors/842356268u/overview
|
||||
// System.Runtime.InteropServices.COMException: 无法在设置线程模式后对其加以更改。 (0x80010106 (RPC_E_CHANGED_MODE))
|
||||
|
||||
var buffer = await provider.ProtectAsync(data.AsBuffer());
|
||||
|
||||
var encBytes = buffer.ToArray();
|
||||
|
||||
return encBytes;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("Windows10.0.10240.0")]
|
||||
static async Task<byte[]> ProtectCore2Async(byte[] data) => await await Task.Factory.StartNew(async () => await ProtectCoreAsync(data));
|
||||
|
||||
[SupportedOSPlatform("Windows10.0.10240.0")]
|
||||
static async Task<byte[]> UnprotectCoreAsync(byte[] data)
|
||||
{
|
||||
var provider = GetDataProtectionProvider();
|
||||
|
||||
var buffer = await provider.UnprotectAsync(data.AsBuffer());
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("Windows10.0.10240.0")]
|
||||
static async Task<byte[]> UnprotectCore2Async(byte[] data) => await await Task.Factory.StartNew(async () => await UnprotectCoreAsync(data));
|
||||
#endif
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
|
||||
<RootNamespace>System</RootNamespace>
|
||||
<AssemblyName>System.Common.UnitTest</AssemblyName>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
Reference in New Issue
Block a user