diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index e20a33ad7..653ddeb6d 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -49,8 +49,12 @@ jobs:
run: dotnet build ./tests/Common.UnitTest/Common.UnitTest.csproj
- name: dotnet ST.Client.UnitTest build
run: dotnet build ./tests/ST.Client.UnitTest/ST.Client.UnitTest.csproj
+ - name: dotnet ST.Client.Desktop.UnitTest build
+ run: dotnet build ./tests/ST.Client.Desktop.UnitTest/ST.Client.Desktop.UnitTest.csproj
- name: dotnet CommonUnit test
run: dotnet test ./tests/Common.UnitTest/Common.UnitTest.csproj
- name: dotnet ST.Client.UnitTest test
run: dotnet test ./tests/ST.Client.UnitTest/ST.Client.UnitTest.csproj
+ - name: dotnet ST.Client.Desktop.UnitTest test
+ run: dotnet test ./tests/ST.Client.Desktop.UnitTest/ST.Client.Desktop.UnitTest.csproj
diff --git a/SteamTools.Desktop.Linux.sln b/SteamTools.Desktop.Linux.sln
index 17ffba7a3..dbc9be04f 100644
--- a/SteamTools.Desktop.Linux.sln
+++ b/SteamTools.Desktop.Linux.sln
@@ -103,6 +103,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CefNet.Avalonia", "referenc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Tools.MinifyStaticSites", "src\ST.Tools.MinifyStaticSites\ST.Tools.MinifyStaticSites.csproj", "{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Client.Desktop.Console.App", "src\ST.Client.Desktop.Console.App\ST.Client.Desktop.Console.App.csproj", "{CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Client.Desktop.UnitTest", "tests\ST.Client.Desktop.UnitTest\ST.Client.Desktop.UnitTest.csproj", "{E21D0376-0A18-4F46-9ED7-BE4466763B2D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -759,6 +763,38 @@ Global
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}.Release|x86.ActiveCfg = Release|Any CPU
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}.Release|x86.Build.0 = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|x86.ActiveCfg = Debug|x86
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Debug|x86.Build.0 = Debug|x86
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|iPhone.Build.0 = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|x86.ActiveCfg = Release|x86
+ {CFDEC4A2-2757-403D-B90B-1846BCEE1EC4}.Release|x86.Build.0 = Release|x86
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Debug|x86.Build.0 = Debug|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|iPhone.Build.0 = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|x86.ActiveCfg = Release|Any CPU
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -800,6 +836,7 @@ Global
{09591D9E-2186-42F1-B6C6-375326E2CF2E} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
{38A8EE9F-81A8-4B11-A6E9-864A12C43089} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1} = {5A7A506C-4DFF-4941-A9A6-B1182C7D5825}
+ {E21D0376-0A18-4F46-9ED7-BE4466763B2D} = {EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A}
diff --git a/SteamTools.Desktop.Mac.sln b/SteamTools.Desktop.Mac.sln
index a3abec280..386dd3de3 100644
--- a/SteamTools.Desktop.Mac.sln
+++ b/SteamTools.Desktop.Mac.sln
@@ -63,6 +63,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Tools.AreaImport", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CefNet.Avalonia", "references\CefNet\CefNet.Avalonia\CefNet.Avalonia.csproj", "{9A533027-82BD-40CB-BB32-77F75F6FDDC7}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Client.Desktop.Console.App", "src\ST.Client.Desktop.Console.App\ST.Client.Desktop.Console.App.csproj", "{A621E551-010C-4397-9C15-66D470B4D98E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaGif", "references\AvaloniaGif\AvaloniaGif\AvaloniaGif.csproj", "{FD444E97-E851-4FF2-A3F1-498C6A3BF098}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Client.Desktop.UnitTest", "tests\ST.Client.Desktop.UnitTest\ST.Client.Desktop.UnitTest.csproj", "{B8597B2B-12B4-4B44-9F37-98BAF3CCD560}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -559,6 +565,78 @@ Global
{9A533027-82BD-40CB-BB32-77F75F6FDDC7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{9A533027-82BD-40CB-BB32-77F75F6FDDC7}.Release|x86.ActiveCfg = Release|Any CPU
{9A533027-82BD-40CB-BB32-77F75F6FDDC7}.Release|x86.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|x86.ActiveCfg = Debug|x86
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Debug|x86.Build.0 = Debug|x86
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|Any CPU.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|iPhone.ActiveCfg = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|iPhone.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|x86.ActiveCfg = Release|x86
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Nuget_Release|x86.Build.0 = Release|x86
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|iPhone.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|x86.ActiveCfg = Release|x86
+ {A621E551-010C-4397-9C15-66D470B4D98E}.Release|x86.Build.0 = Release|x86
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Debug|x86.Build.0 = Debug|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|Any CPU.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|iPhone.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|iPhone.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|x86.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Nuget_Release|x86.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|iPhone.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|x86.ActiveCfg = Release|Any CPU
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098}.Release|x86.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Debug|x86.Build.0 = Debug|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|Any CPU.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|iPhone.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|iPhone.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|x86.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Nuget_Release|x86.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|iPhone.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|x86.ActiveCfg = Release|Any CPU
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -582,6 +660,8 @@ Global
{4190F5AE-FFF1-4CB5-A433-FF5403E2BE24} = {2D44BDCF-B70C-4C02-BDC8-4F1DD5066A75}
{536A0A61-97A8-44E9-8258-9D508D54B44B} = {5A7A506C-4DFF-4941-A9A6-B1182C7D5825}
{9A533027-82BD-40CB-BB32-77F75F6FDDC7} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
+ {FD444E97-E851-4FF2-A3F1-498C6A3BF098} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
+ {B8597B2B-12B4-4B44-9F37-98BAF3CCD560} = {EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A}
diff --git a/SteamToolsV2+.sln b/SteamToolsV2+.sln
index f013049fc..01861abfe 100644
--- a/SteamToolsV2+.sln
+++ b/SteamToolsV2+.sln
@@ -107,6 +107,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CefNet.Avalonia", "referenc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Tools.MinifyStaticSites", "src\ST.Tools.MinifyStaticSites\ST.Tools.MinifyStaticSites.csproj", "{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Client.Desktop.Console.App", "src\ST.Client.Desktop.Console.App\ST.Client.Desktop.Console.App.csproj", "{7F104A37-93AF-4EF8-93EA-E8BD76FE8973}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ST.Client.Desktop.UnitTest", "tests\ST.Client.Desktop.UnitTest\ST.Client.Desktop.UnitTest.csproj", "{F544C06A-152E-48CE-9716-8B92F5CB51FF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -795,6 +799,38 @@ Global
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}.Release|x86.ActiveCfg = Release|Any CPU
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1}.Release|x86.Build.0 = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Debug|x86.Build.0 = Debug|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|iPhone.Build.0 = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|x86.ActiveCfg = Release|Any CPU
+ {7F104A37-93AF-4EF8-93EA-E8BD76FE8973}.Release|x86.Build.0 = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Debug|x86.Build.0 = Debug|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|iPhone.Build.0 = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|x86.ActiveCfg = Release|Any CPU
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -838,6 +874,7 @@ Global
{09591D9E-2186-42F1-B6C6-375326E2CF2E} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
{38A8EE9F-81A8-4B11-A6E9-864A12C43089} = {8EB91F53-1062-4E9B-8E4A-096F35EA688D}
{5E8F54E8-02A6-45D9-A7F9-7C9B43705BE1} = {5A7A506C-4DFF-4941-A9A6-B1182C7D5825}
+ {F544C06A-152E-48CE-9716-8B92F5CB51FF} = {EBC9DD0C-F7D0-4A00-B263-E69CF4E194F1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3833E7C5-69BC-4CB3-92CE-A8854AA35D8A}
diff --git a/resources/AppIcon/VisualElements_150.png b/resources/AppIcon/VisualElements_150.png
index 8c5fe9530..a29593906 100644
Binary files a/resources/AppIcon/VisualElements_150.png and b/resources/AppIcon/VisualElements_150.png differ
diff --git a/src/Common.CoreLib/FileEx.cs b/src/Common.CoreLib/FileEx.cs
index 522bbea84..3a67432ae 100644
--- a/src/Common.CoreLib/FileEx.cs
+++ b/src/Common.CoreLib/FileEx.cs
@@ -1,4 +1,4 @@
-namespace System
+namespace System
{
///
/// 文件扩展名(FileExtensions)
@@ -52,5 +52,7 @@
public const string BIN = ".bin";
public const string APNG = ".apng";
+
+ public const string EXE = ".exe";
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Avalonia.App/Program.InitLogDir.cs b/src/ST.Client.Desktop.Avalonia.App/Program.InitLogDir.cs
new file mode 100644
index 000000000..32905bd31
--- /dev/null
+++ b/src/ST.Client.Desktop.Avalonia.App/Program.InitLogDir.cs
@@ -0,0 +1,48 @@
+using NLog;
+using NLog.Common;
+using NLog.Config;
+using NLog.Targets;
+using System.Application.UI;
+using System.IO;
+using NLogLevel = NLog.LogLevel;
+
+#if CONSOLEAPP
+namespace System.Application
+#else
+namespace System.Application.UI
+#endif
+{
+ static partial class Program
+ {
+ public static Logger? logger;
+
+ public static string InitLogDir(string? alias = null)
+ {
+ var logDirPath = Path.Combine(AppContext.BaseDirectory, "Logs");
+ IOPath.DirCreateByNotExists(logDirPath);
+#if StartupTrace
+ StartupTrace.Restart("InitLogDir.IO");
+#endif
+ var logDirPath_ = logDirPath + Path.DirectorySeparatorChar;
+
+ InternalLogger.LogFile = logDirPath_ + "internal-nlog" + alias + ".txt";
+ InternalLogger.LogLevel = NLogLevel.Error;
+ var objConfig = new LoggingConfiguration();
+ var logfile = new FileTarget("logfile")
+ {
+ FileName = logDirPath_ + "nlog-all-${shortdate}" + alias + ".log",
+ Layout = "${longdate}|${level}|${logger}|${message} |${all-event-properties} ${exception:format=tostring}",
+ };
+ objConfig.AddTarget(logfile);
+ objConfig.AddRule(NLogLevel.Error, NLogLevel.Fatal, logfile, "Microsoft.*");
+ objConfig.AddRule(NLogLevel.Error, NLogLevel.Fatal, logfile, "System.Net.Http.*");
+ objConfig.AddRule(AppHelper.DefaultNLoggerMinLevel, NLogLevel.Fatal, logfile, "*");
+#if StartupTrace
+ StartupTrace.Restart("InitLogDir.CreateLoggingConfiguration");
+#endif
+ LogManager.Configuration = objConfig;
+
+ return logDirPath;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Avalonia.App/Program.cs b/src/ST.Client.Desktop.Avalonia.App/Program.cs
index 0c06beb08..b2275dc7a 100644
--- a/src/ST.Client.Desktop.Avalonia.App/Program.cs
+++ b/src/ST.Client.Desktop.Avalonia.App/Program.cs
@@ -5,6 +5,7 @@ using NLog.Targets;
using ReactiveUI;
using System.Application.Services;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
@@ -15,7 +16,6 @@ namespace System.Application.UI
{
static partial class Program
{
- static Logger? logger;
static readonly HashSet exceptions = new();
static readonly object lock_global_ex_log = new();
@@ -166,35 +166,6 @@ namespace System.Application.UI
}
}
- static string InitLogDir()
- {
- var logDirPath = Path.Combine(AppContext.BaseDirectory, "Logs");
- IOPath.DirCreateByNotExists(logDirPath);
-#if StartupTrace
- StartupTrace.Restart("InitLogDir.IO");
-#endif
- var logDirPath_ = logDirPath + Path.DirectorySeparatorChar;
-
- InternalLogger.LogFile = logDirPath_ + "internal-nlog.txt";
- InternalLogger.LogLevel = NLogLevel.Error;
- var objConfig = new LoggingConfiguration();
- var logfile = new FileTarget("logfile")
- {
- FileName = logDirPath_ + "nlog-all-${shortdate}.log",
- Layout = "${longdate}|${level}|${logger}|${message} |${all-event-properties} ${exception:format=tostring}",
- };
- objConfig.AddTarget(logfile);
- objConfig.AddRule(NLogLevel.Error, NLogLevel.Fatal, logfile, "Microsoft.*");
- objConfig.AddRule(NLogLevel.Error, NLogLevel.Fatal, logfile, "System.Net.Http.*");
- objConfig.AddRule(AppHelper.DefaultNLoggerMinLevel, NLogLevel.Fatal, logfile, "*");
-#if StartupTrace
- StartupTrace.Restart("InitLogDir.CreateLoggingConfiguration");
-#endif
- LogManager.Configuration = objConfig;
-
- return logDirPath;
- }
-
///
/// 是否最小化启动
///
diff --git a/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj b/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj
index 33e08f970..4e47e9a11 100644
--- a/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj
+++ b/src/ST.Client.Desktop.Avalonia.App/ST.Client.Desktop.Avalonia.App.csproj
@@ -1,15 +1,15 @@
-
- WinExe
-
- net6.0
- false
-
- System.Application.UI
- Steam++
- Properties\app.manifest
-
+
+ Exe
+
+ net6.0
+ false
+
+ System.Application.UI
+ Steam++
+ Properties\app.manifest
+
Exe
@@ -63,41 +63,41 @@
false
-
-
-
-
- Properties\AssemblyInfo.cs
-
-
+
+
+
+ Properties\AssemblyInfo.cs
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
- %(Filename)
-
-
- Designer
-
-
-
+
+
+ %(Filename)
+
+
+ Designer
+
+
+
@@ -137,23 +137,23 @@
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Avalonia.Demo.App/ST.Client.Desktop.Avalonia.Demo.App.csproj b/src/ST.Client.Desktop.Avalonia.Demo.App/ST.Client.Desktop.Avalonia.Demo.App.csproj
index d840014fa..9c770d941 100644
--- a/src/ST.Client.Desktop.Avalonia.Demo.App/ST.Client.Desktop.Avalonia.Demo.App.csproj
+++ b/src/ST.Client.Desktop.Avalonia.Demo.App/ST.Client.Desktop.Avalonia.Demo.App.csproj
@@ -2,7 +2,7 @@
WinExe
- net5.0
+ net6.0
false
System.Application.UI
diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs
index b8e68cce7..ce4dad812 100644
--- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs
+++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs
@@ -151,9 +151,10 @@ namespace System.Application.UI.Views.Windows
Navigate(vm?.Url ?? WebView3WindowViewModel.AboutBlank);
}
- async void GetLoginUsingSteamClientCookiesAsync()
+ static Task? mGetLoginUsingSteamClientCookiesAsync;
+ static async Task GetLoginUsingSteamClientCookiesAsync()
{
- var value = await ISteamService.Instance.GetLoginUsingSteamClientCookiesAsync();
+ var value = await ISteamService.Instance.GetLoginUsingSteamClientCookiesAsync(runasInvoker: DI.Platform == Platform.Windows);
if (value != default)
{
var url = value.uri.ToString();
@@ -169,6 +170,13 @@ namespace System.Application.UI.Views.Windows
}
}
}
+ }
+
+ async void GetLoginUsingSteamClientCookies()
+ {
+ if (mGetLoginUsingSteamClientCookiesAsync == null)
+ mGetLoginUsingSteamClientCookiesAsync = GetLoginUsingSteamClientCookiesAsync();
+ await mGetLoginUsingSteamClientCookiesAsync;
LoginUsingSteamClientFinishNavigate();
}
@@ -189,7 +197,7 @@ namespace System.Application.UI.Views.Windows
else if (vm.UseLoginUsingSteamClientV2)
{
loginUsingSteamClientState = LoginUsingSteamClientState.Loading;
- GetLoginUsingSteamClientCookiesAsync();
+ GetLoginUsingSteamClientCookies();
}
vm.WhenAnyValue(x => x.Url).WhereNotNull().Subscribe(x =>
{
diff --git a/src/ST.Client.Desktop.Avalonia/ST.Client.Desktop.Avalonia.csproj b/src/ST.Client.Desktop.Avalonia/ST.Client.Desktop.Avalonia.csproj
index 6d555c722..272f7afbb 100644
--- a/src/ST.Client.Desktop.Avalonia/ST.Client.Desktop.Avalonia.csproj
+++ b/src/ST.Client.Desktop.Avalonia/ST.Client.Desktop.Avalonia.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
System
false
diff --git a/src/ST.Client.Desktop.Console.App/DISafeGet.cs b/src/ST.Client.Desktop.Console.App/DISafeGet.cs
new file mode 100644
index 000000000..f8bdbd40c
--- /dev/null
+++ b/src/ST.Client.Desktop.Console.App/DISafeGet.cs
@@ -0,0 +1,16 @@
+using System.Application.Services;
+
+namespace System.Application
+{
+ ///
+ /// 使用单元测试进行检查依赖注入关系是否配置正确
+ ///
+ static class DISafeGet
+ {
+ public static ISteamService GetLoginUsingSteamClientAuth()
+ {
+ Startup.Init(DILevel.HttpClientFactory | DILevel.Steam);
+ return ISteamService.Instance;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Console.App/Program.cs b/src/ST.Client.Desktop.Console.App/Program.cs
new file mode 100644
index 000000000..41afb24ae
--- /dev/null
+++ b/src/ST.Client.Desktop.Console.App/Program.cs
@@ -0,0 +1,46 @@
+using NLog;
+using System;
+using System.Application;
+using System.Application.UI;
+using System.CommandLine;
+using System.CommandLine.Invocation;
+using System.IO;
+using System.Linq;
+using static System.Application.Program;
+using Process = System.Diagnostics.Process;
+
+var logDirPath = InitLogDir("_console");
+
+logger = LogManager.GetCurrentClassLogger();
+
+if (!args.Any())
+{
+ var mainFilePath = AppHelper.ProgramPath;
+ var endsWithMark = DI.Platform == Platform.Windows ? ".console.exe" : ".console";
+ if (mainFilePath.EndsWith(endsWithMark, StringComparison.OrdinalIgnoreCase))
+ {
+ mainFilePath = mainFilePath.Substring(0, mainFilePath.Length - endsWithMark.Length);
+ if (DI.Platform == Platform.Windows) mainFilePath += ".exe";
+ if (File.Exists(mainFilePath))
+ {
+ Process.Start(mainFilePath);
+ return 0;
+ }
+ }
+}
+
+var rootCommand = new RootCommand("命令行工具(Command Line Tools/CLT)");
+
+var glusca = new Command("GetLoginUsingSteamClientAuth", "获取 Steam 客户端自动登录数据");
+glusca.AddAlias("glusca");
+glusca.Handler = CommandHandler.Create(async () =>
+{
+ var s = DISafeGet.GetLoginUsingSteamClientAuth();
+ var r = await s.GetLoginUsingSteamClientAuthAsync(false);
+ var r2 = Serializable.SMPB64U(r);
+ Console.WriteLine(r2);
+});
+rootCommand.AddCommand(glusca);
+
+var r = rootCommand.InvokeAsync(args).Result;
+return r;
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Console.App/ST.Client.Desktop.Console.App.csproj b/src/ST.Client.Desktop.Console.App/ST.Client.Desktop.Console.App.csproj
new file mode 100644
index 000000000..1c9f3de6d
--- /dev/null
+++ b/src/ST.Client.Desktop.Console.App/ST.Client.Desktop.Console.App.csproj
@@ -0,0 +1,86 @@
+
+
+
+ Exe
+ net6.0
+ System.Application
+ Steam++.Console
+ CONSOLEAPP;$(DefineConstants)
+
+
+
+ WINDOWS;$(DefineConstants)
+ ..\ST.Client.Desktop.Avalonia\Application\UI\Assets\Icon.ico
+
+ AnyCPU;x86
+ x86
+
+ win7-x86
+
+
+
+
+
+ MAC;$(DefineConstants)
+
+
+
+ true
+ false
+
+ false
+ link
+ true
+
+ false
+ false
+ false
+ false
+ false
+ false
+ true
+ none
+ false
+
+
+
+
+
+ Properties\AssemblyInfo.cs
+
+
+ Properties\InternalsVisibleTo.cs
+
+
+ Program.InitLogDir.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Steam++.Console.visualelementsmanifest.xml
+ PreserveNewest
+
+
+
+
diff --git a/src/ST.Client.Desktop.Linux/ST.Client.Desktop.Linux.csproj b/src/ST.Client.Desktop.Linux/ST.Client.Desktop.Linux.csproj
index cfeadbd0e..358cb0394 100644
--- a/src/ST.Client.Desktop.Linux/ST.Client.Desktop.Linux.csproj
+++ b/src/ST.Client.Desktop.Linux/ST.Client.Desktop.Linux.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
System.Application
System.Application.SteamTools.Client.Desktop.Linux
diff --git a/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs b/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs
index d5153a8bd..4207670cf 100644
--- a/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs
+++ b/src/ST.Client.Desktop.Linux/Services/Implementation/LinuxDesktopPlatformServiceImpl.cs
@@ -27,7 +27,7 @@ namespace System.Application.Services.Implementation
return vi;
}
- public void SetSystemSessionEnding(Action action)
+ public void SetSystemSessionEnding(Action action)
{
}
@@ -68,5 +68,15 @@ namespace System.Application.Services.Implementation
public void SetLightOrDarkThemeFollowingSystem(bool enable)
{
}
+
+ public Process StartAsInvoker(string fileName)
+ {
+ return Process.Start(fileName);
+ }
+
+ public Process? StartAsInvoker(ProcessStartInfo startInfo)
+ {
+ return Process.Start(startInfo);
+ }
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Mac/ST.Client.Desktop.Mac.csproj b/src/ST.Client.Desktop.Mac/ST.Client.Desktop.Mac.csproj
index d8a02fef1..3d7c8ff94 100644
--- a/src/ST.Client.Desktop.Mac/ST.Client.Desktop.Mac.csproj
+++ b/src/ST.Client.Desktop.Mac/ST.Client.Desktop.Mac.csproj
@@ -1,10 +1,10 @@
-
-
+
+
- net5.0
+ net6.0
System.Application
System.Application.SteamTools.Client.Desktop.Mac
@@ -24,7 +24,7 @@
XAMARIN_MAC;$(DefineConstants)
-
+
MONO_MAC;$(DefineConstants)
@@ -44,13 +44,13 @@
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs b/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs
index 02182e012..f1197c65b 100644
--- a/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs
+++ b/src/ST.Client.Desktop.Mac/Services/Implementation/MacDesktopPlatformServiceImpl.cs
@@ -158,5 +158,15 @@ namespace System.Application.Services.Implementation
public void SetLightOrDarkThemeFollowingSystem(bool enable)
{
}
+
+ public Process StartAsInvoker(string fileName)
+ {
+ return Process.Start(fileName);
+ }
+
+ public Process? StartAsInvoker(ProcessStartInfo startInfo)
+ {
+ return Process.Start(startInfo);
+ }
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop.Windows/ST.Client.Desktop.Windows.csproj b/src/ST.Client.Desktop.Windows/ST.Client.Desktop.Windows.csproj
index b09fcbfd0..6510e46a5 100644
--- a/src/ST.Client.Desktop.Windows/ST.Client.Desktop.Windows.csproj
+++ b/src/ST.Client.Desktop.Windows/ST.Client.Desktop.Windows.csproj
@@ -2,7 +2,7 @@
- net5.0
+ net6.0
System.Application
diff --git a/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs b/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs
index 0dcdda0c4..021093f3e 100644
--- a/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs
+++ b/src/ST.Client.Desktop.Windows/Services/Implementation/WindowsDesktopPlatformServiceImpl.cs
@@ -173,6 +173,17 @@ namespace System.Application.Services.Implementation
static readonly Lazy<(byte[] key, byte[] iv)> mMachineSecretKey = IDesktopPlatformService.GetMachineSecretKey(GetMachineSecretKey);
public (byte[] key, byte[] iv) MachineSecretKey => mMachineSecretKey.Value;
+
+ public Process StartAsInvoker(string fileName)
+ {
+ return Process.Start($"/trustlevel:0x20000 \"{fileName}\"");
+ }
+
+ public Process? StartAsInvoker(ProcessStartInfo startInfo)
+ {
+ startInfo.FileName = $"/trustlevel:0x20000 \"{startInfo.FileName}\"";
+ return Process.Start(startInfo);
+ }
}
}
#pragma warning restore CA1416 // 验证平台兼容性
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/ST.Client.Desktop.csproj b/src/ST.Client.Desktop/ST.Client.Desktop.csproj
index 32a7f5f24..0ecef279b 100644
--- a/src/ST.Client.Desktop/ST.Client.Desktop.csproj
+++ b/src/ST.Client.Desktop/ST.Client.Desktop.csproj
@@ -1,7 +1,7 @@
-
+
- net5.0
+ net6.0
System.Application
System.Application.SteamTools.Client.Desktop
diff --git a/src/ST.Client.Desktop/ServiceCollectionExtensions.cs b/src/ST.Client.Desktop/ServiceCollectionExtensions.cs
index e4b53a07b..f2c1b84ca 100644
--- a/src/ST.Client.Desktop/ServiceCollectionExtensions.cs
+++ b/src/ST.Client.Desktop/ServiceCollectionExtensions.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using System.Application.Services;
using System.Application.Services.Implementation;
@@ -98,7 +98,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
services.AddSingleton();
return services;
- }
+ }
///
/// 添加 Window 窗口viewmodel
///
diff --git a/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs b/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs
index 9934ea14b..21dbf2102 100644
--- a/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs
+++ b/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs
@@ -187,5 +187,14 @@ namespace System.Application.Services
/// 打开桌面图标设置
///
void OpenDesktopIconsSettings();
+
+ ///
+ /// 已正常权限启动进程
+ ///
+ ///
+ ///
+ Process StartAsInvoker(string fileName);
+
+ Process? StartAsInvoker(ProcessStartInfo startInfo);
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/Services/ISteamService.cs b/src/ST.Client.Desktop/Services/ISteamService.cs
index b8761f71c..5aadd5afa 100644
--- a/src/ST.Client.Desktop/Services/ISteamService.cs
+++ b/src/ST.Client.Desktop/Services/ISteamService.cs
@@ -1,6 +1,5 @@
using System.Application.Models;
using System.Collections.Generic;
-using System.IO;
using System.Net;
using System.Threading.Tasks;
@@ -87,9 +86,24 @@ namespace System.Application.Services
ValueTask LoadAppImageAsync(SteamApp app);
///
- /// 获取 Steam 客户端登录 Cookie(用于写入到 WebView3 中免登录)
+ /// Steam 客户端自动登录
///
+ ///
///
- Task<(CookieCollection cookies, Uri uri)> GetLoginUsingSteamClientCookiesAsync();
+ Task<(string steamid, string encrypted_loginkey, string sessionkey, string digest)> GetLoginUsingSteamClientAuthAsync(bool runasInvoker = false);
+
+ ///
+ /// 获取 Steam 客户端自动登录 Cookie(用于写入到 WebView3 中免登录)
+ ///
+ ///
+ ///
+ Task<(CookieCollection cookies, Uri uri)> GetLoginUsingSteamClientCookiesAsync((string steamid, string encrypted_loginkey, string sessionkey, string digest) auth_data);
+
+ ///
+ /// 获取 Steam 客户端自动登录 Cookie(用于写入到 WebView3 中免登录)
+ ///
+ ///
+ ///
+ Task<(CookieCollection cookies, Uri uri)> GetLoginUsingSteamClientCookiesAsync(bool runasInvoker = false);
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/Services/Implementation/SteamServiceImpl.cs b/src/ST.Client.Desktop/Services/Implementation/SteamServiceImpl.cs
index 35af2d243..4f0d466a1 100644
--- a/src/ST.Client.Desktop/Services/Implementation/SteamServiceImpl.cs
+++ b/src/ST.Client.Desktop/Services/Implementation/SteamServiceImpl.cs
@@ -2,6 +2,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Application.Models;
using System.Application.Models.Settings;
+using System.Application.UI;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -378,62 +379,119 @@ namespace System.Application.Services.Implementation
//}
}
- public async Task<(CookieCollection cookies, Uri uri)> GetLoginUsingSteamClientCookiesAsync()
+ public async Task<(string steamid, string encrypted_loginkey, string sessionkey, string digest)> GetLoginUsingSteamClientAuthAsync(bool runasInvoker = false)
{
- const string url_localhost_auth_public = "http://127.0.0.1:27060/auth/?u=public";
- const string url_steamcommunity_checkclientautologin = "https://steamcommunity.com//login/checkclientautologin";
- var uri_steamcommunity_checkclientautologin = new Uri(url_steamcommunity_checkclientautologin);
- try
+ if (runasInvoker)
{
- var client = http.Factory.CreateClient();
- client.Timeout = TimeSpan.FromSeconds(.85);
- var request = new HttpRequestMessage(HttpMethod.Get, url_localhost_auth_public);
- request.Headers.Add("Origin", "https://steamcommunity.com");
- //request.Headers.Add("Accept", MediaTypeNames.JSON);
- request.Headers.UserAgent.ParseAdd(http.PlatformHelper.UserAgent);
- var response = await client.SendAsync(request);
- if (response.IsSuccessStatusCode)
+ if (AppHelper.ProgramPath.EndsWith(FileEx.EXE))
{
- using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
- using var reader = new StreamReader(stream, Encoding.UTF8);
- using var json = new JsonTextReader(reader);
- var jsonObj = JObject.Load(json);
- var steamid = jsonObj["steamid"]!.ToString();
- var encrypted_loginkey = jsonObj["encrypted_loginkey"]!.ToString();
- var sessionkey = jsonObj["sessionkey"]!.ToString();
- var digest = jsonObj["digest"]!.ToString();
-
- request = new HttpRequestMessage(HttpMethod.Post, uri_steamcommunity_checkclientautologin)
+ var consoleProgramPath = AppHelper.ProgramPath.Substring(0, AppHelper.ProgramPath.Length - FileEx.EXE.Length) + ".Console" + FileEx.EXE;
+ string? value = null;
+ if (File.Exists(consoleProgramPath))
{
-#pragma warning disable CS8620 // 由于引用类型的可为 null 性差异,实参不能用于形参。
- Content = new FormUrlEncodedContent(new Dictionary
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = consoleProgramPath + " glusca",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ CreateNoWindow = true,
+ };
+ using var p = platformService.StartAsInvoker(startInfo)!;
+ var reader = p.StandardOutput;
+ StringBuilder sb = new();
+ while (!reader.EndOfStream)
+ {
+ sb.AppendLine(reader.ReadLine());
+ }
+ value = sb.ToString();
+ p.WaitForExit();
+ }
+ if (value != null)
{
- { "steamid", steamid },
- { "encrypted_loginkey", encrypted_loginkey },
- { "sessionkey", sessionkey },
- { "digest", digest },
- }),
-#pragma warning restore CS8620 // 由于引用类型的可为 null 性差异,实参不能用于形参。
- };
- client.Timeout = TimeSpan.FromSeconds(9.75);
- response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
- if (response.IsSuccessStatusCode && response.Headers.TryGetValues("Set-Cookie", out var cookies))
- {
- CookieContainer container = new();
- foreach (var item in cookies)
+ try
+ {
+ var r = Serializable.DMPB64U<(string steamid, string encrypted_loginkey, string sessionkey, string digest)>(value);
+ return r;
+ }
+ catch
{
- if (string.IsNullOrWhiteSpace(item)) continue;
- container.SetCookies(uri_steamcommunity_checkclientautologin, item);
}
- var cookies2 = container.GetCookies(uri_steamcommunity_checkclientautologin);
- return (cookies2, uri_steamcommunity_checkclientautologin);
}
}
}
- catch (OperationCanceledException)
+ else
{
+ const string url_localhost_auth_public = "http://127.0.0.1:27060/auth/?u=public";
+ try
+ {
+ var client = http.Factory.CreateClient();
+ client.Timeout = TimeSpan.FromSeconds(.85);
+ var request = new HttpRequestMessage(HttpMethod.Get, url_localhost_auth_public);
+ request.Headers.Add("Origin", "https://steamcommunity.com");
+ request.Headers.Add("Accept", MediaTypeNames.JSON);
+ request.Headers.UserAgent.ParseAdd(http.PlatformHelper.UserAgent);
+ var response = await client.SendAsync(request);
+ if (response.IsSuccessStatusCode)
+ {
+ using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(stream, Encoding.UTF8);
+ using var json = new JsonTextReader(reader);
+ var jsonObj = JObject.Load(json);
+ var steamid = jsonObj["steamid"]!.ToString();
+ var encrypted_loginkey = jsonObj["encrypted_loginkey"]!.ToString();
+ var sessionkey = jsonObj["sessionkey"]!.ToString();
+ var digest = jsonObj["digest"]!.ToString();
+ return (steamid, encrypted_loginkey, sessionkey, digest);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ }
}
return default;
}
+
+ public async Task<(CookieCollection cookies, Uri uri)> GetLoginUsingSteamClientCookiesAsync((string steamid, string encrypted_loginkey, string sessionkey, string digest) auth_data)
+ {
+ if (auth_data == default) return default;
+
+ const string url_steamcommunity_checkclientautologin = "https://steamcommunity.com//login/checkclientautologin";
+ var uri_steamcommunity_checkclientautologin = new Uri(url_steamcommunity_checkclientautologin);
+ var request = new HttpRequestMessage(HttpMethod.Post, uri_steamcommunity_checkclientautologin)
+ {
+#pragma warning disable CS8620 // 由于引用类型的可为 null 性差异,实参不能用于形参。
+ Content = new FormUrlEncodedContent(new Dictionary
+ {
+ { "steamid", auth_data.steamid },
+ { "encrypted_loginkey", auth_data.encrypted_loginkey },
+ { "sessionkey", auth_data.sessionkey },
+ { "digest", auth_data.digest },
+ }),
+#pragma warning restore CS8620 // 由于引用类型的可为 null 性差异,实参不能用于形参。
+ };
+ var client = http.Factory.CreateClient();
+ client.Timeout = TimeSpan.FromSeconds(9.75);
+ var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
+ if (response.IsSuccessStatusCode && response.Headers.TryGetValues("Set-Cookie", out var cookies))
+ {
+ CookieContainer container = new();
+ foreach (var item in cookies)
+ {
+ if (string.IsNullOrWhiteSpace(item)) continue;
+ container.SetCookies(uri_steamcommunity_checkclientautologin, item);
+ }
+ var cookies2 = container.GetCookies(uri_steamcommunity_checkclientautologin);
+ return (cookies2, uri_steamcommunity_checkclientautologin);
+ }
+
+ return default;
+ }
+
+ public async Task<(CookieCollection cookies, Uri uri)> GetLoginUsingSteamClientCookiesAsync(bool runasInvoker = false)
+ {
+ var auth_data = await GetLoginUsingSteamClientAuthAsync(runasInvoker);
+ var r = await GetLoginUsingSteamClientCookiesAsync(auth_data);
+ return r;
+ }
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/UI/AppHelper.cs b/src/ST.Client.Desktop/UI/AppHelper.cs
index bc75d0c39..24ee844cb 100644
--- a/src/ST.Client.Desktop/UI/AppHelper.cs
+++ b/src/ST.Client.Desktop/UI/AppHelper.cs
@@ -29,7 +29,7 @@ namespace System.Application.UI
var mainModule = Process.GetCurrentProcess().MainModule;
if (mainModule == null)
throw new ArgumentNullException(nameof(mainModule));
- ProgramPath = mainModule.FileName;
+ ProgramPath = mainModule.FileName!;
if (ProgramPath == null)
throw new ArgumentNullException(nameof(ProgramPath));
var programName = Path.GetFileName(ProgramPath);
diff --git a/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs
index 5d9d2bc65..ce4377fb8 100644
--- a/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs
+++ b/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.cs
@@ -113,7 +113,7 @@ namespace System.Application.UI.ViewModels
TimeoutErrorMessage = AppResources.User_SteamFastLoginTimeoutErrorMessage,
IsSecurity = true,
//UseLoginUsingSteamClient = true,
- UseLoginUsingSteamClientV2 = true,
+ UseLoginUsingSteamClientV2 = false,
};
async void _OnStreamResponseFilterResourceLoadComplete(string url, Stream data)
{
diff --git a/src/ST.Services.CloudService.Models/Services.CloudService/Constants.cs b/src/ST.Services.CloudService.Models/Services.CloudService/Constants.cs
index 838ba24db..703b31910 100644
--- a/src/ST.Services.CloudService.Models/Services.CloudService/Constants.cs
+++ b/src/ST.Services.CloudService.Models/Services.CloudService/Constants.cs
@@ -1,4 +1,5 @@
using System.Application.Properties;
+using System.ComponentModel;
using System.Diagnostics;
using Xamarin.Essentials;
@@ -86,11 +87,22 @@ namespace System.Application.Services.CloudService
{
if (DI.DeviceIdiom == DeviceIdiom.Desktop && DI.Platform != Platform.UWP)
{
- Process.Start(new ProcessStartInfo
+ try
{
- FileName = url,
- UseShellExecute = true,
- });
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = url,
+ UseShellExecute = true,
+ });
+ }
+ catch (Win32Exception e)
+ {
+#if MVVM_VM
+ // [Win32Exception: 找不到应用程序] 39次报告
+ // 疑似缺失没有默认浏览器设置会导致此异常,可能与杀毒软件有关
+ Toast.Show(e.GetAllMessage());
+#endif
+ }
}
else
{
diff --git a/src/ST.Services.CloudService.ViewModels/ST.Services.CloudService.ViewModels.csproj b/src/ST.Services.CloudService.ViewModels/ST.Services.CloudService.ViewModels.csproj
index f7cc7925f..e0d0493fa 100644
--- a/src/ST.Services.CloudService.ViewModels/ST.Services.CloudService.ViewModels.csproj
+++ b/src/ST.Services.CloudService.ViewModels/ST.Services.CloudService.ViewModels.csproj
@@ -40,6 +40,7 @@
+
diff --git a/src/ST.Tools.Win7Troubleshoot/ST.Tools.Win7Troubleshoot.csproj b/src/ST.Tools.Win7Troubleshoot/ST.Tools.Win7Troubleshoot.csproj
index 966db9e64..ca6715985 100644
--- a/src/ST.Tools.Win7Troubleshoot/ST.Tools.Win7Troubleshoot.csproj
+++ b/src/ST.Tools.Win7Troubleshoot/ST.Tools.Win7Troubleshoot.csproj
@@ -1,4 +1,4 @@
-
+
WinExe
@@ -56,7 +56,7 @@
- steam++.Win7.visualelementsmanifest.xml
+ Steam++.Win7.visualelementsmanifest.xml
PreserveNewest
diff --git a/src/ST/Properties/InternalsVisibleTo.cs b/src/ST/Properties/InternalsVisibleTo.cs
index aedba9403..09efc58c1 100644
--- a/src/ST/Properties/InternalsVisibleTo.cs
+++ b/src/ST/Properties/InternalsVisibleTo.cs
@@ -1,4 +1,5 @@
-using System.Runtime.CompilerServices;
+using System.Runtime.CompilerServices;
using static System.Properties.ThisAssembly;
-[assembly: InternalsVisibleTo("System.Application.SteamTools.Client.UnitTest" + PublicKey)]
\ No newline at end of file
+[assembly: InternalsVisibleTo("System.Application.SteamTools.Client.UnitTest" + PublicKey)]
+[assembly: InternalsVisibleTo("System.Application.SteamTools.Client.Desktop.UnitTest" + PublicKey)]
\ No newline at end of file
diff --git a/src/Startup2.cs b/src/Startup2.cs
index 1b50a269e..5cdc083f2 100644
--- a/src/Startup2.cs
+++ b/src/Startup2.cs
@@ -1,4 +1,4 @@
-#if !__MOBILE__
+#if !__MOBILE__ && !CONSOLEAPP
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;
@@ -116,17 +116,24 @@ namespace System.Application
static void ConfigureDemandServices(IServiceCollection services, DILevel level)
{
var hasMainProcessRequired = level.HasFlag(DILevel.MainProcessRequired);
+
#if !__MOBILE__
+#if !CONSOLEAPP
HasNotifyIcon = hasMainProcessRequired;
+#endif
#if !UI_DEMO
// 桌面平台服务 此项放在其他通用业务实现服务之前
services.AddDesktopPlatformService();
#endif
#endif
+#if !CONSOLEAPP
var hasGUI = level.HasFlag(DILevel.GUI);
var hasServerApiClient = level.HasFlag(DILevel.ServerApiClient);
+#endif
var hasHttpClientFactory = level.HasFlag(DILevel.HttpClientFactory);
+#if !CONSOLEAPP
var hasHttpProxy = level.HasFlag(DILevel.HttpProxy);
+#endif
var hasHosts = level.HasFlag(DILevel.Hosts);
var hasSteam = level.HasFlag(DILevel.Steam);
@@ -134,6 +141,7 @@ namespace System.Application
StartupTrace.Restart("DI.ConfigureDemandServices.Calc");
#endif
+#if !CONSOLEAPP
if (hasGUI)
{
// 添加 Toast 提示服务
@@ -186,8 +194,13 @@ namespace System.Application
StartupTrace.Restart("DI.ConfigureDemandServices.GUI");
#endif
}
+#endif
- if (hasHttpClientFactory || hasServerApiClient)
+ if (hasHttpClientFactory
+#if !CONSOLEAPP
+ || hasServerApiClient
+#endif
+ )
{
#if __MOBILE__
// 添加 Http 平台助手移动端实现
@@ -220,6 +233,8 @@ namespace System.Application
#if StartupTrace
StartupTrace.Restart("DI.ConfigureDemandServices.ScriptManager");
#endif
+
+#if !CONSOLEAPP
if (hasHttpProxy)
{
// 通用 Http 代理服务
@@ -228,7 +243,9 @@ namespace System.Application
StartupTrace.Restart("DI.ConfigureDemandServices.HttpProxy");
#endif
}
+#endif
+#if !CONSOLEAPP
if (hasServerApiClient)
{
// 添加 app 配置项
@@ -260,7 +277,9 @@ namespace System.Application
StartupTrace.Restart("DI.ConfigureDemandServices.ServerApiClient");
#endif
}
+#endif
+#if !CONSOLEAPP
// 添加通知服务
AddNotificationService();
#if StartupTrace
@@ -273,6 +292,7 @@ namespace System.Application
#endif
services.AddNotificationService();
}
+#endif
#if !__MOBILE__
//if (hasGUI || hasServerApiClient)
@@ -281,6 +301,7 @@ namespace System.Application
// //services.AddConfigFileService();
//}
+#if !CONSOLEAPP
if (hasHosts)
{
// hosts 文件助手服务
@@ -289,6 +310,7 @@ namespace System.Application
StartupTrace.Restart("DI.ConfigureDemandServices.HostsFileService");
#endif
}
+#endif
if (hasSteam)
{
@@ -308,6 +330,7 @@ namespace System.Application
#endif
}
+#if !CONSOLEAPP
if (hasMainProcessRequired)
{
// 应用程序更新服务
@@ -329,6 +352,7 @@ namespace System.Application
StartupTrace.Restart("DI.ConfigureDemandServices.NotifyIcon");
#endif
}
+#endif
#endif
}
@@ -341,6 +365,7 @@ namespace System.Application
}
#endif
+#if !CONSOLEAPP
static AppSettings AppSettings
{
get
@@ -397,15 +422,16 @@ namespace System.Application
}
}
}
+#endif
-#if !__MOBILE__
+#if !__MOBILE__ && !CONSOLEAPP
public static bool HasNotifyIcon { get; private set; }
-#if !UI_DEMO
+#if !UI_DEMO && !CONSOLEAPP
sealed class NotifyIconImpl : NotifyIcon, INotifyIcon { }
#endif
-#if WINDOWS
+#if WINDOWS && !CONSOLEAPP
//sealed class Win32NotifyIconWindow : MainWindow, INotifyIconWindow
//{
// sealed class Win32WindowImpl : Avalonia.Win32.WindowImpl
@@ -535,6 +561,7 @@ namespace System.Application
}
#endif
+#if !CONSOLEAPP
///
internal static async void ActiveUserPost(ActiveUserType type)
{
@@ -580,6 +607,7 @@ namespace System.Application
Log.Error(nameof(App), e, "ActiveUserPost");
}
}
+#endif
}
#if StartupTrace
diff --git a/tests/ST.Client.Desktop.UnitTest/DISafeGetTest.cs b/tests/ST.Client.Desktop.UnitTest/DISafeGetTest.cs
new file mode 100644
index 000000000..9c0288cb1
--- /dev/null
+++ b/tests/ST.Client.Desktop.UnitTest/DISafeGetTest.cs
@@ -0,0 +1,26 @@
+using NUnit.Framework;
+using System.Linq;
+
+namespace System.Application
+{
+ public class DISafeGetTest
+ {
+ [Test]
+ public void Reflection()
+ {
+ var methods = typeof(DISafeGet).GetMethods().Where(x => x.IsStatic && x.GetParameters().Length == 0);
+
+ foreach (var method in methods)
+ {
+ try
+ {
+ method.Invoke(null, Array.Empty