mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Add ability to switch powershell instance
This commit is contained in:
@@ -52,7 +52,6 @@ internal sealed partial class Activation : IActivation
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ICurrentWindowReference currentWindowReference;
|
||||
private readonly ITaskContext taskContext;
|
||||
//private readonly WeakReference<MainWindow> mainWindowReference = new(default!);
|
||||
private readonly SemaphoreSlim activateSemaphore = new(1);
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity;
|
||||
|
||||
/// <summary>
|
||||
@@ -15,6 +13,11 @@ internal sealed partial class SettingEntry
|
||||
/// </summary>
|
||||
public const string GamePath = "GamePath";
|
||||
|
||||
/// <summary>
|
||||
/// PowerShell 路径
|
||||
/// </summary>
|
||||
public const string PowerShellPath = "PowerShellPath";
|
||||
|
||||
/// <summary>
|
||||
/// 空的历史记录卡池是否可见
|
||||
/// </summary>
|
||||
|
||||
@@ -60,4 +60,6 @@ LPTHREAD_START_ROUTINE
|
||||
MINMAXINFO
|
||||
|
||||
// System.Com
|
||||
CWMO_FLAGS
|
||||
CWMO_FLAGS
|
||||
|
||||
//IShellLinkW
|
||||
@@ -267,6 +267,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 选择 PowerShell 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string FilePickerPowerShellCommit {
|
||||
get {
|
||||
return ResourceManager.GetString("FilePickerPowerShellCommit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 欢迎使用胡桃 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -5415,6 +5424,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 PowerShell 路径 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageSettingSetPowerShellPathHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageSettingSetPowerShellPathHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 赞助我们 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -186,6 +186,9 @@
|
||||
<data name="FilePickerImportCommit" xml:space="preserve">
|
||||
<value>导入</value>
|
||||
</data>
|
||||
<data name="FilePickerPowerShellCommit" xml:space="preserve">
|
||||
<value>选择 PowerShell</value>
|
||||
</data>
|
||||
<data name="GuideWindowTitle" xml:space="preserve">
|
||||
<value>欢迎使用胡桃</value>
|
||||
</data>
|
||||
@@ -1958,6 +1961,9 @@
|
||||
<data name="ViewPageSettingSetGamePathHint" xml:space="preserve">
|
||||
<value>设置游戏路径时,请选择游戏本体(YuanShen.exe 或 GenshinImpact.exe)而不是启动器(launcher.exe)</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSetPowerShellPathHeader" xml:space="preserve">
|
||||
<value>PowerShell 路径</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingSponsorNavigate" xml:space="preserve">
|
||||
<value>赞助我们</value>
|
||||
</data>
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Game;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Service;
|
||||
|
||||
@@ -34,6 +38,7 @@ internal sealed partial class AppOptions : DbStoreOptions
|
||||
};
|
||||
|
||||
private string? gamePath;
|
||||
private string? powerShellPath;
|
||||
private bool? isEmptyHistoryWishVisible;
|
||||
private BackdropType? backdropType;
|
||||
private CultureInfo? currentCulture;
|
||||
@@ -49,6 +54,15 @@ internal sealed partial class AppOptions : DbStoreOptions
|
||||
set => SetOption(ref gamePath, SettingEntry.GamePath, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerShell 路径
|
||||
/// </summary>
|
||||
public string PowerShellPath
|
||||
{
|
||||
get => GetOption(ref powerShellPath, SettingEntry.PowerShellPath, GetPowerShellLocationOrEmpty());
|
||||
set => SetOption(ref powerShellPath, SettingEntry.PowerShellPath, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏路径
|
||||
/// </summary>
|
||||
@@ -111,4 +125,24 @@ internal sealed partial class AppOptions : DbStoreOptions
|
||||
{
|
||||
return new(info.NativeName, info.Name);
|
||||
}
|
||||
|
||||
private static string GetPowerShellLocationOrEmpty()
|
||||
{
|
||||
string? paths = Environment.GetEnvironmentVariable("Path");
|
||||
if (!string.IsNullOrEmpty(paths))
|
||||
{
|
||||
foreach (StringSegment path in new StringTokenizer(paths, ';'.ToArray()))
|
||||
{
|
||||
if (path is { HasValue: true, Length: > 0 })
|
||||
{
|
||||
if (path.Value.Contains("WindowsPowerShell", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Path.Combine(path.Value, "powershell.exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -346,7 +346,12 @@ internal sealed partial class GameService : IGameService
|
||||
/// <inheritdoc/>
|
||||
public bool SetGameAccount(GameAccount account)
|
||||
{
|
||||
return RegistryInterop.Set(account);
|
||||
if (string.IsNullOrEmpty(appOptions.PowerShellPath))
|
||||
{
|
||||
ThrowHelper.RuntimeEnvironment(SH.ServiceGameRegisteryInteropPowershellNotFound, default!);
|
||||
}
|
||||
|
||||
return RegistryInterop.Set(account, appOptions.PowerShellPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Win32;
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
@@ -16,15 +15,9 @@ namespace Snap.Hutao.Service.Game;
|
||||
/// </summary>
|
||||
internal static class RegistryInterop
|
||||
{
|
||||
private const string GenshinKey = @"HKEY_CURRENT_USER\Software\miHoYo\原神";
|
||||
private const string SdkKey = "MIHOYOSDK_ADL_PROD_CN_h3123967166";
|
||||
|
||||
private static string? psExecutablePath;
|
||||
|
||||
private static string PsExecutablePath
|
||||
{
|
||||
get => psExecutablePath ??= GetPowerShellLocation();
|
||||
}
|
||||
private const string GenshinPath = @"Software\miHoYo\原神";
|
||||
private const string GenshinKey = $@"HKEY_CURRENT_USER\{GenshinPath}";
|
||||
private const string SdkChineseKey = "MIHOYOSDK_ADL_PROD_CN_h3123967166";
|
||||
|
||||
/// <summary>
|
||||
/// 设置键值
|
||||
@@ -32,8 +25,9 @@ internal static class RegistryInterop
|
||||
/// https://learn.microsoft.com/zh-cn/windows/win32/fileio/maximum-file-path-limitation
|
||||
/// </summary>
|
||||
/// <param name="account">账户</param>
|
||||
/// <param name="powerShellPath">PowerShell 路径</param>
|
||||
/// <returns>账号是否设置</returns>
|
||||
public static bool Set(GameAccount? account)
|
||||
public static bool Set(GameAccount? account, string powerShellPath)
|
||||
{
|
||||
if (account is not null)
|
||||
{
|
||||
@@ -41,15 +35,15 @@ internal static class RegistryInterop
|
||||
string path = $"HKCU:{GenshinKey[@"HKEY_CURRENT_USER\".Length..]}";
|
||||
string command = $"""
|
||||
$value = [Convert]::FromBase64String('{base64}');
|
||||
Set-ItemProperty -Path '{path}' -Name '{SdkKey}' -Value $value -Force;
|
||||
Set-ItemProperty -Path '{path}' -Name '{SdkChineseKey}' -Value $value -Force;
|
||||
""";
|
||||
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
Arguments = command,
|
||||
WorkingDirectory = Path.GetDirectoryName(PsExecutablePath),
|
||||
WorkingDirectory = Path.GetDirectoryName(powerShellPath),
|
||||
CreateNoWindow = true,
|
||||
FileName = PsExecutablePath,
|
||||
FileName = powerShellPath,
|
||||
};
|
||||
|
||||
try
|
||||
@@ -76,7 +70,7 @@ internal static class RegistryInterop
|
||||
/// <returns>当前注册表中的信息</returns>
|
||||
public static string? Get()
|
||||
{
|
||||
object? sdk = Registry.GetValue(GenshinKey, SdkKey, Array.Empty<byte>());
|
||||
object? sdk = Registry.GetValue(GenshinKey, SdkChineseKey, Array.Empty<byte>());
|
||||
|
||||
if (sdk is byte[] bytes)
|
||||
{
|
||||
@@ -85,23 +79,4 @@ internal static class RegistryInterop
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetPowerShellLocation()
|
||||
{
|
||||
string? paths = Environment.GetEnvironmentVariable("Path");
|
||||
ArgumentException.ThrowIfNullOrEmpty(paths);
|
||||
|
||||
foreach (StringSegment path in new StringTokenizer(paths, ';'.ToArray()))
|
||||
{
|
||||
if (path is { HasValue: true, Length: > 0 })
|
||||
{
|
||||
if (path.Value.Contains("WindowsPowerShell", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Path.Combine(path.Value, "powershell.exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw ThrowHelper.RuntimeEnvironment(SH.ServiceGameRegisteryInteropPowershellNotFound, default!);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,14 @@
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetGamePathHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingSetGamePathAction}"
|
||||
Command="{Binding SetPowerShellPathCommand}"
|
||||
Description="{Binding Options.PowerShellPath}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetPowerShellPathHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingDeleteCacheAction}"
|
||||
|
||||
@@ -37,6 +37,7 @@ internal sealed class AvatarProperty : ObservableObject, INameIcon, IAlternating
|
||||
[FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_PhysicalAttackUp.png").ToUri(),
|
||||
[FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_ShieldCostMinus.png").ToUri(),
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private Brush? background;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -64,7 +64,7 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitializeHutaoAnnouncementAsync()
|
||||
private async ValueTask InitializeHutaoAnnouncementAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ using Snap.Hutao.ViewModel.Guide;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.System;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
@@ -117,6 +118,19 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
[Command("SetPowerShellPathCommand")]
|
||||
private async Task SetPowerShellPathAsync()
|
||||
{
|
||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker(PickerLocationId.DocumentsLibrary, SH.FilePickerPowerShellCommit, ".exe");
|
||||
(bool isOk, ValueFile file) = await picker.TryPickSingleFileAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk && Path.GetFileNameWithoutExtension(file).Equals("POWERSHELL", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Options.PowerShellPath = file;
|
||||
}
|
||||
}
|
||||
|
||||
[Command("DeleteGameWebCacheCommand")]
|
||||
private void DeleteGameWebCache()
|
||||
{
|
||||
@@ -148,17 +162,6 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
[Command("ShowSignInWebViewDialogCommand")]
|
||||
private async Task ShowSignInWebViewDialogAsync()
|
||||
{
|
||||
// ContentDialog must be created by main thread.
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
// TODO remove this.
|
||||
// SignInWebViewDialog dialog = serviceProvider.CreateInstance<SignInWebViewDialog>();
|
||||
// await dialog.ShowAsync();
|
||||
}
|
||||
|
||||
[Command("UpdateCheckCommand")]
|
||||
private async Task CheckUpdateAsync()
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ internal static class HutaoEndpoints
|
||||
return $"{HomaSnapGenshinApi}/Announcement/List?locale={locale}";
|
||||
}
|
||||
|
||||
public static string AnnouncementUpload= $"{HomaSnapGenshinApi}/Service/Announcement/Upload";
|
||||
public const string AnnouncementUpload = $"{HomaSnapGenshinApi}/Service/Announcement/Upload";
|
||||
|
||||
public static string GachaLogCompensation(int days)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user