diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d3ac542..0c0a17a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,6 @@ Though upstream [GameFinder](https://github.com/erri120/GameFinder) adheres to [ **WIP**: -- Add [PkgHandlers](https://github.com/Nutzzz/GameCollector/pull/40) to find installed software, and to download free games - Add [DataHandlers](https://github.com/Nutzzz/GameCollector/pull/13) to download metadata and images from online sources ## [Released](https://github.com/Nutzzz/GameCollector/releases) @@ -26,6 +25,7 @@ Though upstream [GameFinder](https://github.com/erri120/GameFinder) adheres to [ ## Added - Upstream: Heroic (GOG): Support Linux native games +- Add Winget package handler to detect installed apps and free game packages ## [4.4.0-1](https://github.com/erri120/GameFinder/compare/v4.3.2.1...v4.4.0.1) - 2024-12-11 @@ -34,6 +34,8 @@ Though upstream [GameFinder](https://github.com/erri120/GameFinder) adheres to [ - Upstream: GOG & Heroic (GOG): Add `BuildId` - Steam: Check for empty manifest file +## [4.3.3-1](https://github.com/Nutzzz/GameCollector/compare/v4.3.2.1...v4.3.3.1) - 2024-10-09 + ### Fixed - Upstream: Wine: `users` instead of `Users` diff --git a/Directory.Build.props b/Directory.Build.props index bc1da74b..ee3d1078 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,5 @@ - net8.0 true 4.5.0 Nutzzz, erri120 @@ -10,6 +9,12 @@ https://github.com/Nutzzz/GameCollector.git MIT + + net8.0-windows10.0.19041.0 + + + net8.0 + diff --git a/Directory.Packages.props b/Directory.Packages.props index b60c374d..fa73cc37 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,6 +18,11 @@ + + + + + diff --git a/GameCollector.sln b/GameCollector.sln index b3c2f573..74597c52 100644 --- a/GameCollector.sln +++ b/GameCollector.sln @@ -4,40 +4,40 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.6.33723.286 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".solutionItems", ".solutionItems", "{87C3DD03-31FE-4D00-B7BF-D492D6299427}" -ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - .gitattributes = .gitattributes - .gitignore = .gitignore - CHANGELOG.md = CHANGELOG.md - LICENSE = LICENSE - README.md = README.md - CONTRIBUTING.md = CONTRIBUTING.md - renovate.json = renovate.json - codecov.yml = codecov.yml - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - Directory.Packages.props = Directory.Packages.props -EndProjectSection + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + CHANGELOG.md = CHANGELOG.md + codecov.yml = codecov.yml + CONTRIBUTING.md = CONTRIBUTING.md + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + Directory.Packages.props = Directory.Packages.props + LICENSE = LICENSE + README.md = README.md + renovate.json = renovate.json + EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.RegistryUtils", "src\GameFinder.RegistryUtils\GameFinder.RegistryUtils.csproj", "{BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.RegistryUtils", "src\GameFinder.RegistryUtils\GameFinder.RegistryUtils.csproj", "{BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.Steam", "src\GameFinder.StoreHandlers.Steam\GameFinder.StoreHandlers.Steam.csproj", "{3CADF882-5158-4D2E-B15C-D54F5FE89B30}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.Steam", "src\GameFinder.StoreHandlers.Steam\GameFinder.StoreHandlers.Steam.csproj", "{3CADF882-5158-4D2E-B15C-D54F5FE89B30}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.GOG", "src\GameFinder.StoreHandlers.GOG\GameFinder.StoreHandlers.GOG.csproj", "{6F00D927-358E-41A4-8DDF-471B1514128B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.GOG", "src\GameFinder.StoreHandlers.GOG\GameFinder.StoreHandlers.GOG.csproj", "{6F00D927-358E-41A4-8DDF-471B1514128B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.EGS", "src\GameFinder.StoreHandlers.EGS\GameFinder.StoreHandlers.EGS.csproj", "{58A62CC7-4A61-4218-9F93-CE85FDF00E15}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.EGS", "src\GameFinder.StoreHandlers.EGS\GameFinder.StoreHandlers.EGS.csproj", "{58A62CC7-4A61-4218-9F93-CE85FDF00E15}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StoreHandlers", "StoreHandlers", "{B765999C-AB3D-495F-9F5E-9108F2D4FE33}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Example", "other\GameFinder.Example\GameFinder.Example.csproj", "{DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Example", "other\GameFinder.Example\GameFinder.Example.csproj", "{DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.Origin", "src\GameFinder.StoreHandlers.Origin\GameFinder.StoreHandlers.Origin.csproj", "{82126DC0-0DF8-4430-9DB7-7326A0192E48}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.Origin", "src\GameFinder.StoreHandlers.Origin\GameFinder.StoreHandlers.Origin.csproj", "{82126DC0-0DF8-4430-9DB7-7326A0192E48}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Common", "src\GameFinder.Common\GameFinder.Common.csproj", "{4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Common", "src\GameFinder.Common\GameFinder.Common.csproj", "{4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Benchmarks", "other\GameFinder.Benchmarks\GameFinder.Benchmarks.csproj", "{E91CA2ED-F46D-484B-8759-E7ADED282647}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Benchmarks", "other\GameFinder.Benchmarks\GameFinder.Benchmarks.csproj", "{E91CA2ED-F46D-484B-8759-E7ADED282647}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Common.Tests", "tests\GameFinder.Common.Tests\GameFinder.Common.Tests.csproj", "{17A107B4-38CF-469F-AE09-AA5795734D48}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Common.Tests", "tests\GameFinder.Common.Tests\GameFinder.Common.Tests.csproj", "{17A107B4-38CF-469F-AE09-AA5795734D48}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EFB4E7DB-DE24-4BDE-B660-DAF1394ECC21}" ProjectSection(SolutionItems) = preProject @@ -49,8 +49,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9C6671E1 tests\Directory.Build.props = tests\Directory.Build.props tests\Directory.Build.targets = tests\Directory.Build.targets tests\NexusMods.Paths.TestingHelpers.props = tests\NexusMods.Paths.TestingHelpers.props - tests\SharedUsings.cs = tests\SharedUsings.cs tests\SharedAssemblyAttributes.cs = tests\SharedAssemblyAttributes.cs + tests\SharedUsings.cs = tests\SharedUsings.cs EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "other", "other", "{7EA29B58-0E2E-4714-81AC-1F86FE253664}" @@ -60,270 +60,465 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "other", "other", "{7EA29B58 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{41011D08-70EF-410D-83E7-7BEAF795494E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.RegistryUtils.Tests", "tests\GameFinder.RegistryUtils.Tests\GameFinder.RegistryUtils.Tests.csproj", "{EAE6E28E-DDA5-417D-985F-57B8ADCCA981}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.RegistryUtils.Tests", "tests\GameFinder.RegistryUtils.Tests\GameFinder.RegistryUtils.Tests.csproj", "{EAE6E28E-DDA5-417D-985F-57B8ADCCA981}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.EGS.Tests", "tests\GameFinder.StoreHandlers.EGS.Tests\GameFinder.StoreHandlers.EGS.Tests.csproj", "{CCC94557-9698-4468-AAE6-69CB28C676E2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.EGS.Tests", "tests\GameFinder.StoreHandlers.EGS.Tests\GameFinder.StoreHandlers.EGS.Tests.csproj", "{CCC94557-9698-4468-AAE6-69CB28C676E2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.GOG.Tests", "tests\GameFinder.StoreHandlers.GOG.Tests\GameFinder.StoreHandlers.GOG.Tests.csproj", "{37E8F2F8-FED5-4722-934F-621C4CE085F4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.GOG.Tests", "tests\GameFinder.StoreHandlers.GOG.Tests\GameFinder.StoreHandlers.GOG.Tests.csproj", "{37E8F2F8-FED5-4722-934F-621C4CE085F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.Origin.Tests", "tests\GameFinder.StoreHandlers.Origin.Tests\GameFinder.StoreHandlers.Origin.Tests.csproj", "{18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.Origin.Tests", "tests\GameFinder.StoreHandlers.Origin.Tests\GameFinder.StoreHandlers.Origin.Tests.csproj", "{18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.Steam.Tests", "tests\GameFinder.StoreHandlers.Steam.Tests\GameFinder.StoreHandlers.Steam.Tests.csproj", "{0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.Steam.Tests", "tests\GameFinder.StoreHandlers.Steam.Tests\GameFinder.StoreHandlers.Steam.Tests.csproj", "{0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtils", "tests\TestUtils\TestUtils.csproj", "{C26BCA96-CF68-41F5-AC55-B24EF0545E4A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils", "tests\TestUtils\TestUtils.csproj", "{C26BCA96-CF68-41F5-AC55-B24EF0545E4A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.EADesktop", "src\GameFinder.StoreHandlers.EADesktop\GameFinder.StoreHandlers.EADesktop.csproj", "{F7807045-BAA2-46F6-81A6-0127FA662AC8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.EADesktop", "src\GameFinder.StoreHandlers.EADesktop\GameFinder.StoreHandlers.EADesktop.csproj", "{F7807045-BAA2-46F6-81A6-0127FA662AC8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.EADesktop.Tests", "tests\GameFinder.StoreHandlers.EADesktop.Tests\GameFinder.StoreHandlers.EADesktop.Tests.csproj", "{519FD898-CFD1-4093-833F-510BE8BD9379}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.EADesktop.Tests", "tests\GameFinder.StoreHandlers.EADesktop.Tests\GameFinder.StoreHandlers.EADesktop.Tests.csproj", "{519FD898-CFD1-4093-833F-510BE8BD9379}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wine", "Wine", "{21F0CD9E-DC99-49E5-B451-A8A111664E6E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Wine", "src\GameFinder.Wine\GameFinder.Wine.csproj", "{F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Wine", "src\GameFinder.Wine\GameFinder.Wine.csproj", "{F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Wine.Tests", "tests\GameFinder.Wine.Tests\GameFinder.Wine.Tests.csproj", "{C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Wine.Tests", "tests\GameFinder.Wine.Tests\GameFinder.Wine.Tests.csproj", "{C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.Xbox", "src\GameFinder.StoreHandlers.Xbox\GameFinder.StoreHandlers.Xbox.csproj", "{2F75FCA7-DCE5-4162-B2AE-24994D14FC03}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.Xbox", "src\GameFinder.StoreHandlers.Xbox\GameFinder.StoreHandlers.Xbox.csproj", "{2F75FCA7-DCE5-4162-B2AE-24994D14FC03}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.StoreHandlers.Xbox.Tests", "tests\GameFinder.StoreHandlers.Xbox.Tests\GameFinder.StoreHandlers.Xbox.Tests.csproj", "{7D04AF8D-E8AE-44DB-AB36-5452594DC789}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.StoreHandlers.Xbox.Tests", "tests\GameFinder.StoreHandlers.Xbox.Tests\GameFinder.StoreHandlers.Xbox.Tests.csproj", "{7D04AF8D-E8AE-44DB-AB36-5452594DC789}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder", "src\GameFinder\GameFinder.csproj", "{8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder", "src\GameFinder\GameFinder.csproj", "{8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}" + ProjectSection(ProjectDependencies) = postProject + {7D1B9F43-C54A-4903-9839-AAE845A41592} = {7D1B9F43-C54A-4903-9839-AAE845A41592} + EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameFinder.Launcher.Heroic", "src\GameFinder.Launcher.Heroic\GameFinder.Launcher.Heroic.csproj", "{F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameFinder.Launcher.Heroic", "src\GameFinder.Launcher.Heroic\GameFinder.Launcher.Heroic.csproj", "{F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.Common", "src\GameCollector.Common\GameCollector.Common.csproj", "{C1BA59AD-3143-4102-96F0-07D745198398}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.Common", "src\GameCollector.Common\GameCollector.Common.csproj", "{C1BA59AD-3143-4102-96F0-07D745198398}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.SQLiteUtils", "src\GameCollector.SQLiteUtils\GameCollector.SQLiteUtils.csproj", "{B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.SQLiteUtils", "src\GameCollector.SQLiteUtils\GameCollector.SQLiteUtils.csproj", "{B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.YamlUtils", "src\GameCollector.YamlUtils\GameCollector.YamlUtils.csproj", "{FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.YamlUtils", "src\GameCollector.YamlUtils\GameCollector.YamlUtils.csproj", "{FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Amazon", "src\GameCollector.StoreHandlers.Amazon\GameCollector.StoreHandlers.Amazon.csproj", "{158A060B-0036-4CE0-8C4B-CDD2F876A1ED}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Amazon", "src\GameCollector.StoreHandlers.Amazon\GameCollector.StoreHandlers.Amazon.csproj", "{158A060B-0036-4CE0-8C4B-CDD2F876A1ED}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Arc", "src\GameCollector.StoreHandlers.Arc\GameCollector.StoreHandlers.Arc.csproj", "{F411D87A-7833-44F4-9B41-814C50292CAE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Arc", "src\GameCollector.StoreHandlers.Arc\GameCollector.StoreHandlers.Arc.csproj", "{F411D87A-7833-44F4-9B41-814C50292CAE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.BattleNet", "src\GameCollector.StoreHandlers.BattleNet\GameCollector.StoreHandlers.BattleNet.csproj", "{82823466-00E1-4D38-8CEF-1E7955B4C5A4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.BattleNet", "src\GameCollector.StoreHandlers.BattleNet\GameCollector.StoreHandlers.BattleNet.csproj", "{82823466-00E1-4D38-8CEF-1E7955B4C5A4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.BigFish", "src\GameCollector.StoreHandlers.BigFish\GameCollector.StoreHandlers.BigFish.csproj", "{FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.BigFish", "src\GameCollector.StoreHandlers.BigFish\GameCollector.StoreHandlers.BigFish.csproj", "{FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.GameJolt", "src\GameCollector.StoreHandlers.GameJolt\GameCollector.StoreHandlers.GameJolt.csproj", "{FAEE9122-5E0D-4246-A9FC-A346295A82FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.GameJolt", "src\GameCollector.StoreHandlers.GameJolt\GameCollector.StoreHandlers.GameJolt.csproj", "{FAEE9122-5E0D-4246-A9FC-A346295A82FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Humble", "src\GameCollector.StoreHandlers.Humble\GameCollector.StoreHandlers.Humble.csproj", "{5074B706-14AD-4104-A2DA-EBBD36B19255}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Humble", "src\GameCollector.StoreHandlers.Humble\GameCollector.StoreHandlers.Humble.csproj", "{5074B706-14AD-4104-A2DA-EBBD36B19255}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.IGClient", "src\GameCollector.StoreHandlers.IGClient\GameCollector.StoreHandlers.IGClient.csproj", "{06AA6AE5-2FAC-4761-9D44-CA11A3912256}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.IGClient", "src\GameCollector.StoreHandlers.IGClient\GameCollector.StoreHandlers.IGClient.csproj", "{06AA6AE5-2FAC-4761-9D44-CA11A3912256}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Itch", "src\GameCollector.StoreHandlers.Itch\GameCollector.StoreHandlers.Itch.csproj", "{C8DE7215-67F5-494E-B7AB-088270CB28C3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Itch", "src\GameCollector.StoreHandlers.Itch\GameCollector.StoreHandlers.Itch.csproj", "{C8DE7215-67F5-494E-B7AB-088270CB28C3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Legacy", "src\GameCollector.StoreHandlers.Legacy\GameCollector.StoreHandlers.Legacy.csproj", "{64EA04B2-A7A7-4184-AB99-180F084033BC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Legacy", "src\GameCollector.StoreHandlers.Legacy\GameCollector.StoreHandlers.Legacy.csproj", "{64EA04B2-A7A7-4184-AB99-180F084033BC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Oculus", "src\GameCollector.StoreHandlers.Oculus\GameCollector.StoreHandlers.Oculus.csproj", "{487FD285-16EB-46AD-AF82-9F058D2A4141}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Oculus", "src\GameCollector.StoreHandlers.Oculus\GameCollector.StoreHandlers.Oculus.csproj", "{487FD285-16EB-46AD-AF82-9F058D2A4141}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Paradox", "src\GameCollector.StoreHandlers.Paradox\GameCollector.StoreHandlers.Paradox.csproj", "{DD16375A-6112-49F4-A4D3-9B1524B952B3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Paradox", "src\GameCollector.StoreHandlers.Paradox\GameCollector.StoreHandlers.Paradox.csproj", "{DD16375A-6112-49F4-A4D3-9B1524B952B3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Plarium", "src\GameCollector.StoreHandlers.Plarium\GameCollector.StoreHandlers.Plarium.csproj", "{6147F764-C8B3-4D80-9311-52974100B916}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Plarium", "src\GameCollector.StoreHandlers.Plarium\GameCollector.StoreHandlers.Plarium.csproj", "{6147F764-C8B3-4D80-9311-52974100B916}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Riot", "src\GameCollector.StoreHandlers.Riot\GameCollector.StoreHandlers.Riot.csproj", "{0E5D8910-979B-46B8-B32F-12298707F892}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Riot", "src\GameCollector.StoreHandlers.Riot\GameCollector.StoreHandlers.Riot.csproj", "{0E5D8910-979B-46B8-B32F-12298707F892}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.RobotCache", "src\GameCollector.StoreHandlers.RobotCache\GameCollector.StoreHandlers.RobotCache.csproj", "{7D1B9F43-C54A-4903-9839-AAE845A41592}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.RobotCache", "src\GameCollector.StoreHandlers.RobotCache\GameCollector.StoreHandlers.RobotCache.csproj", "{7D1B9F43-C54A-4903-9839-AAE845A41592}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Rockstar", "src\GameCollector.StoreHandlers.Rockstar\GameCollector.StoreHandlers.Rockstar.csproj", "{67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Rockstar", "src\GameCollector.StoreHandlers.Rockstar\GameCollector.StoreHandlers.Rockstar.csproj", "{67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.Ubisoft", "src\GameCollector.StoreHandlers.Ubisoft\GameCollector.StoreHandlers.Ubisoft.csproj", "{E939182C-42EC-474A-952C-064FE757CDCA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.Ubisoft", "src\GameCollector.StoreHandlers.Ubisoft\GameCollector.StoreHandlers.Ubisoft.csproj", "{E939182C-42EC-474A-952C-064FE757CDCA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.StoreHandlers.WargamingNet", "src\GameCollector.StoreHandlers.WargamingNet\GameCollector.StoreHandlers.WargamingNet.csproj", "{6368DFB4-1E79-4D24-9603-17449F0C2F71}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.StoreHandlers.WargamingNet", "src\GameCollector.StoreHandlers.WargamingNet\GameCollector.StoreHandlers.WargamingNet.csproj", "{6368DFB4-1E79-4D24-9603-17449F0C2F71}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EmuHandlers", "EmuHandlers", "{1F5F230D-146C-4794-A2E6-F9C13279D721}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.EmuHandlers.Dolphin", "src\GameCollector.EmuHandlers.Dolphin\GameCollector.EmuHandlers.Dolphin.csproj", "{6173D1F4-48C2-4B14-B907-C7A746CF081D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.EmuHandlers.Dolphin", "src\GameCollector.EmuHandlers.Dolphin\GameCollector.EmuHandlers.Dolphin.csproj", "{6173D1F4-48C2-4B14-B907-C7A746CF081D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.EmuHandlers.MAME", "src\GameCollector.EmuHandlers.MAME\GameCollector.EmuHandlers.MAME.csproj", "{EA0A79A3-639B-4983-A28F-1D07EC1113C7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PkgHandlers", "PkgHandlers", "{55345886-D1F6-4733-9943-1283AF39CEA5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCollector.EmuHandlers.MAME", "src\GameCollector.EmuHandlers.MAME\GameCollector.EmuHandlers.MAME.csproj", "{EA0A79A3-639B-4983-A28F-1D07EC1113C7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameCollector.PkgHandlers.Winget", "src\GameCollector.PkgHandlers.Winget\GameCollector.PkgHandlers.Winget.csproj", "{7C74842C-69FE-4908-BA71-210652A15744}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataHandlers", "DataHandlers", "{82816E34-196A-4304-8A28-BF22FA937DF0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Debug|x64.ActiveCfg = Debug|x64 + {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Debug|x64.Build.0 = Debug|x64 {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Release|Any CPU.Build.0 = Release|Any CPU + {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Release|x64.ActiveCfg = Release|x64 + {BED6FB0B-C200-4651-BCE8-2DD9210FC7CF}.Release|x64.Build.0 = Release|x64 {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Debug|x64.ActiveCfg = Debug|x64 + {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Debug|x64.Build.0 = Debug|x64 {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Release|Any CPU.Build.0 = Release|Any CPU + {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Release|x64.ActiveCfg = Release|x64 + {3CADF882-5158-4D2E-B15C-D54F5FE89B30}.Release|x64.Build.0 = Release|x64 {6F00D927-358E-41A4-8DDF-471B1514128B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6F00D927-358E-41A4-8DDF-471B1514128B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F00D927-358E-41A4-8DDF-471B1514128B}.Debug|x64.ActiveCfg = Debug|x64 + {6F00D927-358E-41A4-8DDF-471B1514128B}.Debug|x64.Build.0 = Debug|x64 {6F00D927-358E-41A4-8DDF-471B1514128B}.Release|Any CPU.ActiveCfg = Release|Any CPU {6F00D927-358E-41A4-8DDF-471B1514128B}.Release|Any CPU.Build.0 = Release|Any CPU + {6F00D927-358E-41A4-8DDF-471B1514128B}.Release|x64.ActiveCfg = Release|x64 + {6F00D927-358E-41A4-8DDF-471B1514128B}.Release|x64.Build.0 = Release|x64 {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Debug|x64.ActiveCfg = Debug|x64 + {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Debug|x64.Build.0 = Debug|x64 {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Release|Any CPU.ActiveCfg = Release|Any CPU {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Release|Any CPU.Build.0 = Release|Any CPU + {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Release|x64.ActiveCfg = Release|x64 + {58A62CC7-4A61-4218-9F93-CE85FDF00E15}.Release|x64.Build.0 = Release|x64 {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Debug|x64.ActiveCfg = Debug|x64 + {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Debug|x64.Build.0 = Debug|x64 {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Release|Any CPU.ActiveCfg = Release|Any CPU {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Release|Any CPU.Build.0 = Release|Any CPU + {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Release|x64.ActiveCfg = Release|x64 + {DFC0FA99-91A5-4CC0-A12C-1CAA84D2CB53}.Release|x64.Build.0 = Release|x64 {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Debug|x64.ActiveCfg = Debug|x64 + {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Debug|x64.Build.0 = Debug|x64 {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Release|Any CPU.ActiveCfg = Release|Any CPU {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Release|Any CPU.Build.0 = Release|Any CPU + {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Release|x64.ActiveCfg = Release|x64 + {82126DC0-0DF8-4430-9DB7-7326A0192E48}.Release|x64.Build.0 = Release|x64 {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Debug|x64.ActiveCfg = Debug|x64 + {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Debug|x64.Build.0 = Debug|x64 {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Release|Any CPU.ActiveCfg = Release|Any CPU {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Release|Any CPU.Build.0 = Release|Any CPU + {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Release|x64.ActiveCfg = Release|x64 + {4DD3B263-D44B-4D4D-9FDD-9AA6DA8DEDDD}.Release|x64.Build.0 = Release|x64 {E91CA2ED-F46D-484B-8759-E7ADED282647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E91CA2ED-F46D-484B-8759-E7ADED282647}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E91CA2ED-F46D-484B-8759-E7ADED282647}.Debug|x64.ActiveCfg = Debug|x64 + {E91CA2ED-F46D-484B-8759-E7ADED282647}.Debug|x64.Build.0 = Debug|x64 {E91CA2ED-F46D-484B-8759-E7ADED282647}.Release|Any CPU.ActiveCfg = Release|Any CPU {E91CA2ED-F46D-484B-8759-E7ADED282647}.Release|Any CPU.Build.0 = Release|Any CPU + {E91CA2ED-F46D-484B-8759-E7ADED282647}.Release|x64.ActiveCfg = Release|x64 + {E91CA2ED-F46D-484B-8759-E7ADED282647}.Release|x64.Build.0 = Release|x64 {17A107B4-38CF-469F-AE09-AA5795734D48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {17A107B4-38CF-469F-AE09-AA5795734D48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17A107B4-38CF-469F-AE09-AA5795734D48}.Debug|x64.ActiveCfg = Debug|x64 + {17A107B4-38CF-469F-AE09-AA5795734D48}.Debug|x64.Build.0 = Debug|x64 {17A107B4-38CF-469F-AE09-AA5795734D48}.Release|Any CPU.ActiveCfg = Release|Any CPU {17A107B4-38CF-469F-AE09-AA5795734D48}.Release|Any CPU.Build.0 = Release|Any CPU + {17A107B4-38CF-469F-AE09-AA5795734D48}.Release|x64.ActiveCfg = Release|x64 + {17A107B4-38CF-469F-AE09-AA5795734D48}.Release|x64.Build.0 = Release|x64 {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Debug|x64.ActiveCfg = Debug|x64 + {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Debug|x64.Build.0 = Debug|x64 {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Release|Any CPU.ActiveCfg = Release|Any CPU {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Release|Any CPU.Build.0 = Release|Any CPU + {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Release|x64.ActiveCfg = Release|x64 + {EAE6E28E-DDA5-417D-985F-57B8ADCCA981}.Release|x64.Build.0 = Release|x64 {CCC94557-9698-4468-AAE6-69CB28C676E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CCC94557-9698-4468-AAE6-69CB28C676E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCC94557-9698-4468-AAE6-69CB28C676E2}.Debug|x64.ActiveCfg = Debug|x64 + {CCC94557-9698-4468-AAE6-69CB28C676E2}.Debug|x64.Build.0 = Debug|x64 {CCC94557-9698-4468-AAE6-69CB28C676E2}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCC94557-9698-4468-AAE6-69CB28C676E2}.Release|Any CPU.Build.0 = Release|Any CPU + {CCC94557-9698-4468-AAE6-69CB28C676E2}.Release|x64.ActiveCfg = Release|x64 + {CCC94557-9698-4468-AAE6-69CB28C676E2}.Release|x64.Build.0 = Release|x64 {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Debug|x64.ActiveCfg = Debug|x64 + {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Debug|x64.Build.0 = Debug|x64 {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Release|Any CPU.Build.0 = Release|Any CPU + {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Release|x64.ActiveCfg = Release|x64 + {37E8F2F8-FED5-4722-934F-621C4CE085F4}.Release|x64.Build.0 = Release|x64 {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Debug|x64.ActiveCfg = Debug|x64 + {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Debug|x64.Build.0 = Debug|x64 {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Release|Any CPU.Build.0 = Release|Any CPU + {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Release|x64.ActiveCfg = Release|x64 + {18AD8AE9-4AAF-4322-8F8E-2DBCDC40D9A9}.Release|x64.Build.0 = Release|x64 {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Debug|x64.ActiveCfg = Debug|x64 + {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Debug|x64.Build.0 = Debug|x64 {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Release|Any CPU.ActiveCfg = Release|Any CPU {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Release|Any CPU.Build.0 = Release|Any CPU + {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Release|x64.ActiveCfg = Release|x64 + {0A89AE18-0C30-4FD6-874A-7DC5DE6FB391}.Release|x64.Build.0 = Release|x64 {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Debug|x64.ActiveCfg = Debug|x64 + {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Debug|x64.Build.0 = Debug|x64 {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Release|Any CPU.ActiveCfg = Release|Any CPU {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Release|Any CPU.Build.0 = Release|Any CPU + {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Release|x64.ActiveCfg = Release|x64 + {C26BCA96-CF68-41F5-AC55-B24EF0545E4A}.Release|x64.Build.0 = Release|x64 {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Debug|x64.ActiveCfg = Debug|x64 + {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Debug|x64.Build.0 = Debug|x64 {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Release|Any CPU.Build.0 = Release|Any CPU + {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Release|x64.ActiveCfg = Release|x64 + {F7807045-BAA2-46F6-81A6-0127FA662AC8}.Release|x64.Build.0 = Release|x64 {519FD898-CFD1-4093-833F-510BE8BD9379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {519FD898-CFD1-4093-833F-510BE8BD9379}.Debug|Any CPU.Build.0 = Debug|Any CPU + {519FD898-CFD1-4093-833F-510BE8BD9379}.Debug|x64.ActiveCfg = Debug|x64 + {519FD898-CFD1-4093-833F-510BE8BD9379}.Debug|x64.Build.0 = Debug|x64 {519FD898-CFD1-4093-833F-510BE8BD9379}.Release|Any CPU.ActiveCfg = Release|Any CPU {519FD898-CFD1-4093-833F-510BE8BD9379}.Release|Any CPU.Build.0 = Release|Any CPU + {519FD898-CFD1-4093-833F-510BE8BD9379}.Release|x64.ActiveCfg = Release|x64 + {519FD898-CFD1-4093-833F-510BE8BD9379}.Release|x64.Build.0 = Release|x64 {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Debug|x64.ActiveCfg = Debug|x64 + {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Debug|x64.Build.0 = Debug|x64 {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Release|Any CPU.ActiveCfg = Release|Any CPU {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Release|Any CPU.Build.0 = Release|Any CPU + {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Release|x64.ActiveCfg = Release|x64 + {F553AEEA-FD48-4C84-B5A1-7CC31F2F76D5}.Release|x64.Build.0 = Release|x64 {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Debug|x64.ActiveCfg = Debug|x64 + {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Debug|x64.Build.0 = Debug|x64 {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Release|Any CPU.ActiveCfg = Release|Any CPU {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Release|Any CPU.Build.0 = Release|Any CPU + {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Release|x64.ActiveCfg = Release|x64 + {C1FA1F2C-8CC2-4EFF-8206-8B52A1B4FBFE}.Release|x64.Build.0 = Release|x64 {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Debug|x64.ActiveCfg = Debug|x64 + {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Debug|x64.Build.0 = Debug|x64 {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Release|Any CPU.Build.0 = Release|Any CPU + {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Release|x64.ActiveCfg = Release|x64 + {2F75FCA7-DCE5-4162-B2AE-24994D14FC03}.Release|x64.Build.0 = Release|x64 {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Debug|x64.ActiveCfg = Debug|x64 + {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Debug|x64.Build.0 = Debug|x64 {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Release|Any CPU.Build.0 = Release|Any CPU + {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Release|x64.ActiveCfg = Release|x64 + {7D04AF8D-E8AE-44DB-AB36-5452594DC789}.Release|x64.Build.0 = Release|x64 {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Debug|x64.ActiveCfg = Debug|x64 + {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Debug|x64.Build.0 = Debug|x64 {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Release|Any CPU.Build.0 = Release|Any CPU + {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Release|x64.ActiveCfg = Release|x64 + {8F9D4B7D-5269-4053-BB20-9DB7B5F8DF8E}.Release|x64.Build.0 = Release|x64 {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Debug|x64.ActiveCfg = Debug|x64 + {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Debug|x64.Build.0 = Debug|x64 {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Release|Any CPU.ActiveCfg = Release|Any CPU {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Release|Any CPU.Build.0 = Release|Any CPU + {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Release|x64.ActiveCfg = Release|x64 + {F0805D2B-7B2C-4F54-A09A-D1FBE02F3D35}.Release|x64.Build.0 = Release|x64 {C1BA59AD-3143-4102-96F0-07D745198398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C1BA59AD-3143-4102-96F0-07D745198398}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1BA59AD-3143-4102-96F0-07D745198398}.Debug|x64.ActiveCfg = Debug|x64 + {C1BA59AD-3143-4102-96F0-07D745198398}.Debug|x64.Build.0 = Debug|x64 {C1BA59AD-3143-4102-96F0-07D745198398}.Release|Any CPU.ActiveCfg = Release|Any CPU {C1BA59AD-3143-4102-96F0-07D745198398}.Release|Any CPU.Build.0 = Release|Any CPU + {C1BA59AD-3143-4102-96F0-07D745198398}.Release|x64.ActiveCfg = Release|x64 + {C1BA59AD-3143-4102-96F0-07D745198398}.Release|x64.Build.0 = Release|x64 {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Debug|x64.ActiveCfg = Debug|x64 + {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Debug|x64.Build.0 = Debug|x64 {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Release|Any CPU.Build.0 = Release|Any CPU + {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Release|x64.ActiveCfg = Release|x64 + {B399A554-BDD6-4A2D-A71A-5CC88FF4DE4C}.Release|x64.Build.0 = Release|x64 {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Debug|x64.ActiveCfg = Debug|x64 + {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Debug|x64.Build.0 = Debug|x64 {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Release|Any CPU.ActiveCfg = Release|Any CPU {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Release|Any CPU.Build.0 = Release|Any CPU + {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Release|x64.ActiveCfg = Release|x64 + {FD458F9E-A2BC-4E60-B26A-F8DEC2AD7DDD}.Release|x64.Build.0 = Release|x64 {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Debug|x64.ActiveCfg = Debug|x64 + {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Debug|x64.Build.0 = Debug|x64 {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Release|Any CPU.Build.0 = Release|Any CPU + {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Release|x64.ActiveCfg = Release|x64 + {158A060B-0036-4CE0-8C4B-CDD2F876A1ED}.Release|x64.Build.0 = Release|x64 {F411D87A-7833-44F4-9B41-814C50292CAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F411D87A-7833-44F4-9B41-814C50292CAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F411D87A-7833-44F4-9B41-814C50292CAE}.Debug|x64.ActiveCfg = Debug|x64 + {F411D87A-7833-44F4-9B41-814C50292CAE}.Debug|x64.Build.0 = Debug|x64 {F411D87A-7833-44F4-9B41-814C50292CAE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F411D87A-7833-44F4-9B41-814C50292CAE}.Release|Any CPU.Build.0 = Release|Any CPU + {F411D87A-7833-44F4-9B41-814C50292CAE}.Release|x64.ActiveCfg = Release|x64 + {F411D87A-7833-44F4-9B41-814C50292CAE}.Release|x64.Build.0 = Release|x64 {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Debug|x64.ActiveCfg = Debug|x64 + {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Debug|x64.Build.0 = Debug|x64 {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Release|Any CPU.ActiveCfg = Release|Any CPU {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Release|Any CPU.Build.0 = Release|Any CPU + {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Release|x64.ActiveCfg = Release|x64 + {82823466-00E1-4D38-8CEF-1E7955B4C5A4}.Release|x64.Build.0 = Release|x64 {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Debug|x64.ActiveCfg = Debug|x64 + {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Debug|x64.Build.0 = Debug|x64 {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Release|Any CPU.ActiveCfg = Release|Any CPU {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Release|Any CPU.Build.0 = Release|Any CPU + {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Release|x64.ActiveCfg = Release|x64 + {FDDB677C-FFDC-4D3F-BB63-CA385BE8B217}.Release|x64.Build.0 = Release|x64 {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Debug|x64.ActiveCfg = Debug|x64 + {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Debug|x64.Build.0 = Debug|x64 {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Release|Any CPU.Build.0 = Release|Any CPU + {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Release|x64.ActiveCfg = Release|x64 + {FAEE9122-5E0D-4246-A9FC-A346295A82FD}.Release|x64.Build.0 = Release|x64 {5074B706-14AD-4104-A2DA-EBBD36B19255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5074B706-14AD-4104-A2DA-EBBD36B19255}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5074B706-14AD-4104-A2DA-EBBD36B19255}.Debug|x64.ActiveCfg = Debug|x64 + {5074B706-14AD-4104-A2DA-EBBD36B19255}.Debug|x64.Build.0 = Debug|x64 {5074B706-14AD-4104-A2DA-EBBD36B19255}.Release|Any CPU.ActiveCfg = Release|Any CPU {5074B706-14AD-4104-A2DA-EBBD36B19255}.Release|Any CPU.Build.0 = Release|Any CPU + {5074B706-14AD-4104-A2DA-EBBD36B19255}.Release|x64.ActiveCfg = Release|x64 + {5074B706-14AD-4104-A2DA-EBBD36B19255}.Release|x64.Build.0 = Release|x64 {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Debug|Any CPU.Build.0 = Debug|Any CPU + {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Debug|x64.ActiveCfg = Debug|x64 + {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Debug|x64.Build.0 = Debug|x64 {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Release|Any CPU.ActiveCfg = Release|Any CPU {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Release|Any CPU.Build.0 = Release|Any CPU + {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Release|x64.ActiveCfg = Release|x64 + {06AA6AE5-2FAC-4761-9D44-CA11A3912256}.Release|x64.Build.0 = Release|x64 {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Debug|x64.ActiveCfg = Debug|x64 + {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Debug|x64.Build.0 = Debug|x64 {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Release|Any CPU.Build.0 = Release|Any CPU + {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Release|x64.ActiveCfg = Release|x64 + {C8DE7215-67F5-494E-B7AB-088270CB28C3}.Release|x64.Build.0 = Release|x64 {64EA04B2-A7A7-4184-AB99-180F084033BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {64EA04B2-A7A7-4184-AB99-180F084033BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64EA04B2-A7A7-4184-AB99-180F084033BC}.Debug|x64.ActiveCfg = Debug|x64 + {64EA04B2-A7A7-4184-AB99-180F084033BC}.Debug|x64.Build.0 = Debug|x64 {64EA04B2-A7A7-4184-AB99-180F084033BC}.Release|Any CPU.ActiveCfg = Release|Any CPU {64EA04B2-A7A7-4184-AB99-180F084033BC}.Release|Any CPU.Build.0 = Release|Any CPU + {64EA04B2-A7A7-4184-AB99-180F084033BC}.Release|x64.ActiveCfg = Release|x64 + {64EA04B2-A7A7-4184-AB99-180F084033BC}.Release|x64.Build.0 = Release|x64 {487FD285-16EB-46AD-AF82-9F058D2A4141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {487FD285-16EB-46AD-AF82-9F058D2A4141}.Debug|Any CPU.Build.0 = Debug|Any CPU + {487FD285-16EB-46AD-AF82-9F058D2A4141}.Debug|x64.ActiveCfg = Debug|x64 + {487FD285-16EB-46AD-AF82-9F058D2A4141}.Debug|x64.Build.0 = Debug|x64 {487FD285-16EB-46AD-AF82-9F058D2A4141}.Release|Any CPU.ActiveCfg = Release|Any CPU {487FD285-16EB-46AD-AF82-9F058D2A4141}.Release|Any CPU.Build.0 = Release|Any CPU + {487FD285-16EB-46AD-AF82-9F058D2A4141}.Release|x64.ActiveCfg = Release|x64 + {487FD285-16EB-46AD-AF82-9F058D2A4141}.Release|x64.Build.0 = Release|x64 {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Debug|x64.ActiveCfg = Debug|x64 + {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Debug|x64.Build.0 = Debug|x64 {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Release|Any CPU.Build.0 = Release|Any CPU + {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Release|x64.ActiveCfg = Release|x64 + {DD16375A-6112-49F4-A4D3-9B1524B952B3}.Release|x64.Build.0 = Release|x64 {6147F764-C8B3-4D80-9311-52974100B916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6147F764-C8B3-4D80-9311-52974100B916}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6147F764-C8B3-4D80-9311-52974100B916}.Debug|x64.ActiveCfg = Debug|x64 + {6147F764-C8B3-4D80-9311-52974100B916}.Debug|x64.Build.0 = Debug|x64 {6147F764-C8B3-4D80-9311-52974100B916}.Release|Any CPU.ActiveCfg = Release|Any CPU {6147F764-C8B3-4D80-9311-52974100B916}.Release|Any CPU.Build.0 = Release|Any CPU + {6147F764-C8B3-4D80-9311-52974100B916}.Release|x64.ActiveCfg = Release|x64 + {6147F764-C8B3-4D80-9311-52974100B916}.Release|x64.Build.0 = Release|x64 {0E5D8910-979B-46B8-B32F-12298707F892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0E5D8910-979B-46B8-B32F-12298707F892}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E5D8910-979B-46B8-B32F-12298707F892}.Debug|x64.ActiveCfg = Debug|x64 + {0E5D8910-979B-46B8-B32F-12298707F892}.Debug|x64.Build.0 = Debug|x64 {0E5D8910-979B-46B8-B32F-12298707F892}.Release|Any CPU.ActiveCfg = Release|Any CPU {0E5D8910-979B-46B8-B32F-12298707F892}.Release|Any CPU.Build.0 = Release|Any CPU + {0E5D8910-979B-46B8-B32F-12298707F892}.Release|x64.ActiveCfg = Release|x64 + {0E5D8910-979B-46B8-B32F-12298707F892}.Release|x64.Build.0 = Release|x64 {7D1B9F43-C54A-4903-9839-AAE845A41592}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D1B9F43-C54A-4903-9839-AAE845A41592}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D1B9F43-C54A-4903-9839-AAE845A41592}.Debug|x64.ActiveCfg = Debug|x64 + {7D1B9F43-C54A-4903-9839-AAE845A41592}.Debug|x64.Build.0 = Debug|x64 {7D1B9F43-C54A-4903-9839-AAE845A41592}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D1B9F43-C54A-4903-9839-AAE845A41592}.Release|Any CPU.Build.0 = Release|Any CPU + {7D1B9F43-C54A-4903-9839-AAE845A41592}.Release|x64.ActiveCfg = Release|x64 + {7D1B9F43-C54A-4903-9839-AAE845A41592}.Release|x64.Build.0 = Release|x64 {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Debug|x64.ActiveCfg = Debug|x64 + {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Debug|x64.Build.0 = Debug|x64 {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Release|Any CPU.ActiveCfg = Release|Any CPU {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Release|Any CPU.Build.0 = Release|Any CPU + {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Release|x64.ActiveCfg = Release|x64 + {67B56585-D06F-4EEC-9CB0-E3CB5CC1AE6E}.Release|x64.Build.0 = Release|x64 {E939182C-42EC-474A-952C-064FE757CDCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E939182C-42EC-474A-952C-064FE757CDCA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E939182C-42EC-474A-952C-064FE757CDCA}.Debug|x64.ActiveCfg = Debug|x64 + {E939182C-42EC-474A-952C-064FE757CDCA}.Debug|x64.Build.0 = Debug|x64 {E939182C-42EC-474A-952C-064FE757CDCA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E939182C-42EC-474A-952C-064FE757CDCA}.Release|Any CPU.Build.0 = Release|Any CPU + {E939182C-42EC-474A-952C-064FE757CDCA}.Release|x64.ActiveCfg = Release|x64 + {E939182C-42EC-474A-952C-064FE757CDCA}.Release|x64.Build.0 = Release|x64 {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Debug|x64.ActiveCfg = Debug|x64 + {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Debug|x64.Build.0 = Debug|x64 {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Release|Any CPU.ActiveCfg = Release|Any CPU {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Release|Any CPU.Build.0 = Release|Any CPU + {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Release|x64.ActiveCfg = Release|x64 + {6368DFB4-1E79-4D24-9603-17449F0C2F71}.Release|x64.Build.0 = Release|x64 {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Debug|x64.ActiveCfg = Debug|x64 + {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Debug|x64.Build.0 = Debug|x64 {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Release|Any CPU.ActiveCfg = Release|Any CPU {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Release|Any CPU.Build.0 = Release|Any CPU + {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Release|x64.ActiveCfg = Release|x64 + {6173D1F4-48C2-4B14-B907-C7A746CF081D}.Release|x64.Build.0 = Release|x64 {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Debug|x64.ActiveCfg = Debug|x64 + {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Debug|x64.Build.0 = Debug|x64 {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Release|Any CPU.Build.0 = Release|Any CPU + {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Release|x64.ActiveCfg = Release|x64 + {EA0A79A3-639B-4983-A28F-1D07EC1113C7}.Release|x64.Build.0 = Release|x64 + {7C74842C-69FE-4908-BA71-210652A15744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C74842C-69FE-4908-BA71-210652A15744}.Debug|x64.ActiveCfg = Debug|x64 + {7C74842C-69FE-4908-BA71-210652A15744}.Debug|x64.Build.0 = Debug|x64 + {7C74842C-69FE-4908-BA71-210652A15744}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C74842C-69FE-4908-BA71-210652A15744}.Release|x64.ActiveCfg = Release|x64 + {7C74842C-69FE-4908-BA71-210652A15744}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -378,6 +573,8 @@ Global {1F5F230D-146C-4794-A2E6-F9C13279D721} = {EFB4E7DB-DE24-4BDE-B660-DAF1394ECC21} {6173D1F4-48C2-4B14-B907-C7A746CF081D} = {1F5F230D-146C-4794-A2E6-F9C13279D721} {EA0A79A3-639B-4983-A28F-1D07EC1113C7} = {1F5F230D-146C-4794-A2E6-F9C13279D721} + {55345886-D1F6-4733-9943-1283AF39CEA5} = {EFB4E7DB-DE24-4BDE-B660-DAF1394ECC21} + {7C74842C-69FE-4908-BA71-210652A15744} = {55345886-D1F6-4733-9943-1283AF39CEA5} {82816E34-196A-4304-8A28-BF22FA937DF0} = {EFB4E7DB-DE24-4BDE-B660-DAF1394ECC21} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/README.md b/README.md index 498272fb..8e8a131f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ .NET library for finding games. GameCollector expands on upstream GameFinder (which is primarily designed to support modding tools), by adding additional supported store launchers, emulators, and data sources, and includes additional information about each game (sufficient for a multi-store game launcher such as [GLC](https://github.com/Solaire/GLC)). This fork is indebted to erri120's hard work, but as [he is reticent](https://github.com/erri120/GameFinder/issues/49) to expand the scope of GameFinder, GameCollector continues with a different philosophy. -The following launchers and emulators are supported: +The following launchers, emulators, and package managers are supported: | handler | package | | -- | -- | @@ -36,6 +36,7 @@ The following launchers and emulators are supported: | [Steam](#steam) | [![Nuget](https://img.shields.io/nuget/v/GameCollector.StoreHandlers.Steam)](https://www.nuget.org/packages/GameCollector.StoreHandlers.Steam) [![Nuget](https://img.shields.io/nuget/v/GameFinder.StoreHandlers.Steam?color=red&label=upstream)](https://www.nuget.org/packages/GameFinder.StoreHandlers.Steam) | | Ubisoft Connect | [![Nuget](https://img.shields.io/nuget/v/GameCollector.StoreHandlers.Ubisoft)](https://www.nuget.org/packages/GameCollector.StoreHandlers.Ubisoft) | | Wargaming.net Game Center | [![Nuget](https://img.shields.io/nuget/v/GameCollector.StoreHandlers.WargamingNet)](https://www.nuget.org/packages/GameCollector.StoreHandlers.WargamingNet) | +| Windows Package Manager | [![Nuget](https://img.shields.io/nuget/v/GameCollector.PkgHandlers.Winget)](https://www.nuget.org/packages/GameCollector.PkgHandlers.Winget) | | [Xbox Game Pass](#xbox-game-pass) | [![Nuget](https://img.shields.io/nuget/v/GameCollector.StoreHandlers.Xbox)](https://www.nuget.org/packages/GameCollector.StoreHandlers.Xbox) [![Nuget](https://img.shields.io/nuget/v/GameFinder.StoreHandlers.Xbox?color=red&label=upstream)](https://www.nuget.org/packages/GameFinder.StoreHandlers.Xbox) | If you are interested in understanding _how_ GameCollector/GameFinder finds these games, check [the upstream wiki](https://github.com/erri120/GameFinder/wiki) for more information (descriptions of the added handlers should eventually be added to a wiki here). @@ -98,6 +99,12 @@ The TGame implementations of GameCollector's handlers inherit a generic GameData The Metadata dictionary may include (depending on available information): "ReleaseDate", "Description", "Developers", "Publishers", "Genres", "ImageUrl", etc. +### Supported Package Managers + +This is a new category of handler for GameCollector. It is Windows-only for now. + +- Winget + ### Supported Emulators This is a new category of handler for GameCollector. They are Windows-only for now. @@ -418,7 +425,7 @@ Self-contained deployments and executables can be [trimmed](https://learn.micros **NOT Trimmable**: -- `GameCollector.StoreHandlers.EADesktop`: This package references `System.Management`, which is **not trimmable** due to COM interop issues. See [dotnet/runtime#78038](https://github.com/dotnet/runtime/issues/78038), [dotnet/runtime#75176](https://github.com/dotnet/runtime/pull/75176) and [dotnet/runtime#61960](https://github.com/dotnet/runtime/issues/61960) for more details. +- `GameCollector.StoreHandlers.EADesktop` and `GameCollector.PkgHandlers.Winget`: These packages reference `System.Management`, which is **not trimmable** due to COM interop issues. See [dotnet/runtime#78038](https://github.com/dotnet/runtime/issues/78038), [dotnet/runtime#75176](https://github.com/dotnet/runtime/pull/75176) and [dotnet/runtime#61960](https://github.com/dotnet/runtime/issues/61960) for more details. I recommend looking at the [project file](./other/GameFinder.Example/GameFinder.Example.csproj) of the example project, if you run into warnings or errors with trimming. diff --git a/codecov.yml b/codecov.yml index 95a801a0..db5c0e8a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -132,6 +132,10 @@ component_management: name: Wargaming.net Game Center paths: - "src/GameCollector.StoreHandlers.WargamingNet/**" + - component_id: pkg_handler_winget + name: Windows Package Manager + paths: + - "src/GameCollector.PkgHandlers.Winget/**" - component_id: emu_handler_dolphin name: Dolphin Emulator paths: diff --git a/other/GameFinder.Benchmarks/GameFinder.Benchmarks.csproj b/other/GameFinder.Benchmarks/GameFinder.Benchmarks.csproj index b31ee1cb..9a75f54c 100644 --- a/other/GameFinder.Benchmarks/GameFinder.Benchmarks.csproj +++ b/other/GameFinder.Benchmarks/GameFinder.Benchmarks.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/other/GameFinder.Example/GameFinder.Example.csproj b/other/GameFinder.Example/GameFinder.Example.csproj index cc84e17a..9fcc40a1 100644 --- a/other/GameFinder.Example/GameFinder.Example.csproj +++ b/other/GameFinder.Example/GameFinder.Example.csproj @@ -9,17 +9,29 @@ publish\ 2f3f5c05-f8b8-4435-901e-1caec9ff8715 ..\..\GameCollector.ico + GameCollector.Program + AnyCPU;x64 + + x64 + net8.0-windows10.0.19041.0 + WINX64 + 10.0.19041.0 + + + AnyCPU + net8.0 + - + - + - + @@ -52,6 +64,10 @@ + + + + diff --git a/other/GameFinder.Example/Options.cs b/other/GameFinder.Example/Options.cs index f51c897c..340e7698 100644 --- a/other/GameFinder.Example/Options.cs +++ b/other/GameFinder.Example/Options.cs @@ -46,9 +46,6 @@ public class Options [Option("gog", HelpText = "Search for GOG GALAXY games", Hidden = true, Group = "Handlers")] public bool GOG { get; set; } = false; - [Option("heroic", HelpText = "Search for games from Heroic", Hidden = true, Group = "Handlers")] - public bool Heroic { get; set; } = false; - [Option("humble", HelpText = "Search for Humble App games", Hidden = true, Group = "Handlers")] public bool Humble { get; set; } = false; @@ -96,10 +93,8 @@ public class Options [Option("steam", HelpText = "Search for Steam games", Hidden = true, Group = "Handlers")] public bool Steam { get; set; } = false; - /* - [Option("tgdb", HelpText = "Search for TheGamesDb.net games", Group = "Handlers")] + [Option("tgdb", HelpText = "Search for TheGamesDb.net games", Hidden = true, Group = "Handlers")] public bool TheGamesDB { get; set; } = false; - */ // alias for "ubisoft" [Option("uplay", HelpText = "Search for Ubisoft Connect games", Hidden = true)] @@ -115,21 +110,41 @@ public class Options [Option("wargaming", HelpText = "Search for Wargaming.Net Game Center games", Hidden = true, Group = "Handlers")] public bool Wargaming { get; set; } = false; +#if WINX64 + [Option("winget", HelpText = "Search for Windows Package Manager packages", Hidden = false, Group = "Handlers")] +#else + [Option("winget", HelpText = "Search for Windows Package Manager packages", Hidden = true, Group = "Handlers")] +#endif + public bool Winget { get; set; } = false; + [Option("xbox", HelpText = "Search for Xbox Games Pass games", Hidden = true, Group = "Handlers")] public bool Xbox { get; set; } = false; [Option('s', "steamapi", HelpText = "Specify Steam API key from (optional)", MetaValue = "KEY")] public string? SteamAPI { get; set; } - /* - [Option('t', "tgdbapi", HelpText = "Specify TheGamesDb.net API key from (optional)", MetaValue = "KEY")] + [Option('t', "tgdbapi", HelpText = "Specify TheGamesDb.net API key from (optional)", Hidden = true, MetaValue = "KEY")] public string? TheGamesDBAPI { get; set; } - */ - [Option('w', "wine", HelpText = "Search for Wine prefixes")] +#if WINX64 + [Option("heroic", HelpText = "Search for games from Heroic", Hidden = true)] +#else + [Option("heroic", HelpText = "Search for games from Heroic", Hidden = false)] +#endif + public bool Heroic { get; set; } = false; + +#if WINX64 + [Option('w', "wine", HelpText = "Search for Wine prefixes", Hidden = true)] +#else + [Option('w', "wine", HelpText = "Search for Wine prefixes", Hidden = false)] +#endif public bool Wine { get; set; } = false; - [Option('b', "bottles", HelpText = "Search for Wine prefixes managed with Bottles")] +#if WINX64 + [Option('b', "bottles", HelpText = "Search for Wine prefixes managed with Bottles", Hidden = true)] +#else + [Option('b', "bottles", HelpText = "Search for Wine prefixes managed with Bottles", Hidden = false)] +#endif public bool Bottles { get; set; } = false; [Option('i', "installed", HelpText = "Only retrieve installed games")] diff --git a/other/GameFinder.Example/Program.cs b/other/GameFinder.Example/Program.cs index 5ef309e3..a9a9b863 100644 --- a/other/GameFinder.Example/Program.cs +++ b/other/GameFinder.Example/Program.cs @@ -37,6 +37,9 @@ using GameCollector.StoreHandlers.Rockstar; using GameCollector.StoreHandlers.Ubisoft; using GameCollector.StoreHandlers.WargamingNet; +#if WINX64 +using GameCollector.PkgHandlers.Winget; +#endif using GameCollector.EmuHandlers.Dolphin; using GameCollector.EmuHandlers.MAME; //using GameCollector.DataHandlers.TheGamesDb; @@ -51,7 +54,6 @@ using IFileSystem = NexusMods.Paths.IFileSystem; using ILogger = Microsoft.Extensions.Logging.ILogger; -[assembly: ExcludeFromCodeCoverage] namespace GameCollector; public static class Program @@ -115,23 +117,22 @@ private async static void Run(Options options, ILogger logger) var settings = new Settings(options.Installed, options.Parent || options.Base, options.Owned, options.Games); - if (options.All) // Enable all emulator and handlers + if (options.All) // Enable all handlers { options.Amazon = true; options.Arc = true; options.BattleNet = true; options.BigFish = true; - //options.Dolphin ??= ""; + //options.Dolphin ??= ""; // needs path options.EA = true; options.Epic = true; options.GameJolt = true; options.GOG = true; - options.Heroic = true; options.Humble = true; options.IG = true; options.Itch = true; options.Legacy = true; - //options.MAME ??= ""; + //options.MAME ??= ""; // needs path options.Oculus = true; options.Origin = true; options.Paradox = true; @@ -140,10 +141,16 @@ private async static void Run(Options options, ILogger logger) options.RobotCache = true; options.Rockstar = true; options.Steam = true; - //options.TheGamesDB = true; + options.TheGamesDB = false; // WIP options.Ubisoft = true; options.Wargaming = true; options.Xbox = true; +#if WINX64 + options.Winget = OperatingSystem.IsWindows(); // Requires TargetFramework net8.0-windows10.0.19041.0 +#else + options.Heroic = OperatingSystem.IsLinux(); + options.Wine = OperatingSystem.IsLinux(); +#endif } if (OperatingSystem.IsWindows()) @@ -186,7 +193,9 @@ private async static void Run(Options options, ILogger logger) if (options.Rockstar) tasks.Add(Task.Run(() => RunRockstarHandler(settings, windowsRegistry, realFileSystem), cancelToken)); if (options.Ubisoft || options.Uplay) tasks.Add(Task.Run(() => RunUbisoftHandler(settings, windowsRegistry, realFileSystem), cancelToken)); if (options.Wargaming || options.WargamingNet) tasks.Add(Task.Run(() => RunWargamingNetHandler(settings, windowsRegistry, realFileSystem), cancelToken)); - +#if WINX64 + if (options.Winget) RunWingetHandler(settings, windowsRegistry, realFileSystem); //tasks.Add(Task.Run(() => RunWingetHandler(settings, windowsRegistry, realFileSystem), cancelToken)); +#endif if (options.Dolphin is not null) { tasks.Add(Task.Run(() => @@ -456,6 +465,20 @@ private static void RunWargamingNetHandler(Settings settings, IRegistry registry LogGamesAndErrors(handler.FindAllGames(settings), logger); } +#if WINX64 + private static void RunWingetHandler(Settings settings, IRegistry registry, IFileSystem fileSystem) + { + var logger = _provider.CreateLogger(nameof(WingetHandler)); + if (OperatingSystem.IsWindows()) + { + var handler = new WingetHandler(registry, fileSystem, logger); //, logger); + LogGamesAndErrors(handler.FindAllGames(settings), logger); + } + else + logger.LogError("Handler requires Windows-only target."); + } +#endif + private static void RunDolphinHandler(Settings settings, IRegistry registry, IFileSystem fileSystem, AbsolutePath path) { var logger = _provider.CreateLogger(nameof(DolphinHandler)); @@ -470,15 +493,16 @@ private static void RunMAMEHandler(Settings settings, IFileSystem fileSystem, Ab LogGamesAndErrors(handler.FindAllGames(settings), logger); } - /* private static async void RunTheGamesDbHandler(IFileSystem fileSystem, string? tgdbApi, Settings settings) { - var logger = _provider.CreateLogger(nameof(TheGamesDbHandler)); + var logger = _provider.CreateLogger("TheGamesDbHandler"); + logger.LogError("Handler not yet implemented."); + /* //var handler = new TheGamesDbHandler(fileSystem, tgdbApi, registry: null, logger); var handler = new TheGamesDbHandler(fileSystem, registry: null, logger); LogGamesAndErrors(handler.FindAllGames(settings), logger); + */ } - */ private static List LogWinePrefixes(IWinePrefixManager prefixManager, ILogger logger) where TWinePrefix : AWinePrefix diff --git a/src/GameCollector.Common/GameCollector.Common.csproj b/src/GameCollector.Common/GameCollector.Common.csproj index 2aaa7a6e..7069ec33 100644 --- a/src/GameCollector.Common/GameCollector.Common.csproj +++ b/src/GameCollector.Common/GameCollector.Common.csproj @@ -1,5 +1,9 @@ + + AnyCPU;x64 + + diff --git a/src/GameCollector.EmuHandlers.Dolphin/GameCollector.EmuHandlers.Dolphin.csproj b/src/GameCollector.EmuHandlers.Dolphin/GameCollector.EmuHandlers.Dolphin.csproj index f0922131..de1c8327 100644 --- a/src/GameCollector.EmuHandlers.Dolphin/GameCollector.EmuHandlers.Dolphin.csproj +++ b/src/GameCollector.EmuHandlers.Dolphin/GameCollector.EmuHandlers.Dolphin.csproj @@ -2,6 +2,7 @@ Library for finding Dolphin ROMs. dolphin dolphin-emu emulator games + AnyCPU;x64 diff --git a/src/GameCollector.EmuHandlers.MAME/GameCollector.EmuHandlers.MAME.csproj b/src/GameCollector.EmuHandlers.MAME/GameCollector.EmuHandlers.MAME.csproj index 6bbc59e9..130a3d92 100644 --- a/src/GameCollector.EmuHandlers.MAME/GameCollector.EmuHandlers.MAME.csproj +++ b/src/GameCollector.EmuHandlers.MAME/GameCollector.EmuHandlers.MAME.csproj @@ -2,6 +2,7 @@ Library for finding MAME ROMs. mame emulator games + AnyCPU;x64 diff --git a/src/GameCollector.PkgHandlers.Winget/Exceptions/WinGetConfigurationException.cs b/src/GameCollector.PkgHandlers.Winget/Exceptions/WinGetConfigurationException.cs new file mode 100644 index 00000000..c04792e9 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/Exceptions/WinGetConfigurationException.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; + +namespace GameCollector.PkgHandlers.Winget.Exceptions; + +public class WinGetConfigurationException : Exception +{ + // WinGet Configuration error codes: + // https://github.com/microsoft/winget-cli/blob/master/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs + public const int WingetConfigErrorInvalidConfigurationFile = unchecked((int)0x8A15C001); + public const int WingetConfigErrorInvalidYaml = unchecked((int)0x8A15C002); + public const int WingetConfigErrorInvalidFieldType = unchecked((int)0x8A15C003); + public const int WingetConfigErrorUnknownConfigurationFileVersion = unchecked((int)0x8A15C004); + public const int WingetConfigErrorSetApplyFailed = unchecked((int)0x8A15C005); + public const int WingetConfigErrorDuplicateIdentifier = unchecked((int)0x8A15C006); + public const int WingetConfigErrorMissingDependency = unchecked((int)0x8A15C007); + public const int WingetConfigErrorDependencyUnsatisfied = unchecked((int)0x8A15C008); + public const int WingetConfigErrorAssertionFailed = unchecked((int)0x8A15C009); + public const int WingetConfigErrorManuallySkipped = unchecked((int)0x8A15C00A); + public const int WingetConfigErrorWarningNotAccepted = unchecked((int)0x8A15C00B); + public const int WingetConfigErrorSetDependencyCycle = unchecked((int)0x8A15C00C); + public const int WingetConfigErrorInvalidFieldValue = unchecked((int)0x8A15C00D); + public const int WingetConfigErrorMissingField = unchecked((int)0x8A15C00E); + + // WinGet Configuration unit error codes: + public const int WinGetConfigUnitNotFound = unchecked((int)0x8A15C101); + public const int WinGetConfigUnitNotFoundRepository = unchecked((int)0x8A15C102); + public const int WinGetConfigUnitMultipleMatches = unchecked((int)0x8A15C103); + public const int WinGetConfigUnitInvokeGet = unchecked((int)0x8A15C104); + public const int WinGetConfigUnitInvokeTest = unchecked((int)0x8A15C105); + public const int WinGetConfigUnitInvokeSet = unchecked((int)0x8A15C106); + public const int WinGetConfigUnitModuleConflict = unchecked((int)0x8A15C107); + public const int WinGetConfigUnitImportModule = unchecked((int)0x8A15C108); + public const int WinGetConfigUnitInvokeInvalidResult = unchecked((int)0x8A15C109); + public const int WinGetConfigUnitSettingConfigRoot = unchecked((int)0x8A15C110); + public const int WinGetConfigUnitImportModuleAdmin = unchecked((int)0x8A15C111); +} diff --git a/src/GameCollector.PkgHandlers.Winget/GameCollector.PkgHandlers.Winget.csproj b/src/GameCollector.PkgHandlers.Winget/GameCollector.PkgHandlers.Winget.csproj new file mode 100644 index 00000000..717bd3fa --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/GameCollector.PkgHandlers.Winget.csproj @@ -0,0 +1,74 @@ + + + Library for finding installed apps and available game packages via Windows Package Manager. + winget windows-package-manager games + net8.0-windows10.0.19041.0 + 10.0.19041.0 + + x64 + + + + + 10.0.19041.0 + Microsoft.Management.Deployment + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + NU1701 + true + none + false + + + NU1701 + true + none + + + + + + + + + + + + + + + + + + + + + diff --git a/src/GameCollector.PkgHandlers.Winget/Microsoft.Management.Deployment.winmd b/src/GameCollector.PkgHandlers.Winget/Microsoft.Management.Deployment.winmd new file mode 100644 index 00000000..fbcc32b2 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/Microsoft.Management.Deployment.winmd @@ -0,0 +1,1892 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + winget-cli/tools/SampleWinGetUWPCaller/AppInstallerCaller/GeneratedFromServer/Microsoft.Management.Deployment.winmd at master · microsoft/winget-cli · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Skip to content + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + winget-cli + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+ +
+
+ +
+ +
+

Footer

+ + + + +
+
+ + + + + © 2024 GitHub, Inc. + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + diff --git a/src/GameCollector.PkgHandlers.Winget/NativeMethods.txt b/src/GameCollector.PkgHandlers.Winget/NativeMethods.txt new file mode 100644 index 00000000..a7650f2c --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/NativeMethods.txt @@ -0,0 +1,7 @@ +CoCreateInstance +CoMarshalInterface +CoUnmarshalInterface +CreateStreamOnHGlobal +HRESULT_FROM_WIN32 +MSHCTX +MSHLFLAGS diff --git a/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClassModel.cs b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClassModel.cs new file mode 100644 index 00000000..992cb0b8 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClassModel.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +internal sealed class ClassModel +{ + /// + /// Gets the interface for the projected class type generated by CsWinRT + /// + public Type? InterfaceType { get; init; } + + /// + /// Gets the projected class type generated by CsWinRT + /// + public Type? ProjectedClassType { get; init; } + + /// + /// Gets the clsids for each context (e.g. OutOfProcProd, OutOfProcDev) + /// + public IReadOnlyDictionary? Clsids { get; init; } + + /// + /// Get CLSID based on the provided context + /// + /// Context + /// CLSID for the provided context. + /// Throw an exception if the clsid context is not available for the current instance. + public Guid GetClsid(ClsidContext context) + { + var clsid = Guid.Empty; + + if (Clsids is not null && !Clsids.TryGetValue(context, out clsid)) + { + throw new InvalidOperationException($"{ProjectedClassType?.FullName} is not implemented in context {context}"); + } + + return clsid; + } + + /// + /// Get IID corresponding to the COM object + /// + /// IID. + public Guid? GetIid() + { + return InterfaceType?.GUID; + } +} diff --git a/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClassesDefinition.cs b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClassesDefinition.cs new file mode 100644 index 00000000..1cdee6e9 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClassesDefinition.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using Microsoft.Management.Deployment; + +namespace GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +internal static class ClassesDefinition +{ + private static Dictionary Classes { get; } = new() + { + [typeof(PackageManager)] = new() + { + ProjectedClassType = typeof(PackageManager), + InterfaceType = typeof(IPackageManager), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("C53A4F16-787E-42A4-B304-29EFFB4BF597"), + [ClsidContext.Dev] = new Guid("74CB3139-B7C5-4B9E-9388-E6616DEA288C"), + }, + }, + + [typeof(FindPackagesOptions)] = new() + { + ProjectedClassType = typeof(FindPackagesOptions), + InterfaceType = typeof(IFindPackagesOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("572DED96-9C60-4526-8F92-EE7D91D38C1A"), + [ClsidContext.Dev] = new Guid("1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96"), + }, + }, + + [typeof(CreateCompositePackageCatalogOptions)] = new() + { + ProjectedClassType = typeof(CreateCompositePackageCatalogOptions), + InterfaceType = typeof(ICreateCompositePackageCatalogOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("526534B8-7E46-47C8-8416-B1685C327D37"), + [ClsidContext.Dev] = new Guid("EE160901-B317-4EA7-9CC6-5355C6D7D8A7"), + }, + }, + + [typeof(InstallOptions)] = new() + { + ProjectedClassType = typeof(InstallOptions), + InterfaceType = typeof(IInstallOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("1095F097-EB96-453B-B4E6-1613637F3B14"), + [ClsidContext.Dev] = new Guid("44FE0580-62F7-44D4-9E91-AA9614AB3E86"), + }, + }, + + [typeof(UninstallOptions)] = new() + { + ProjectedClassType = typeof(UninstallOptions), + InterfaceType = typeof(IUninstallOptions), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("E1D9A11E-9F85-4D87-9C17-2B93143ADB8D"), + [ClsidContext.Dev] = new Guid("AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C"), + }, + }, + + [typeof(PackageMatchFilter)] = new() + { + ProjectedClassType = typeof(PackageMatchFilter), + InterfaceType = typeof(IPackageMatchFilter), + Clsids = new Dictionary + { + [ClsidContext.Prod] = new Guid("D02C9DAF-99DC-429C-B503-4E504E4AB000"), + [ClsidContext.Dev] = new Guid("3F85B9F4-487A-4C48-9035-2903F8A6D9E8"), + }, + }, + }; + + /// + /// Get CLSID based on the provided context for the specified type + /// + /// Projected class type + /// Context + /// CLSID for the provided context and type, or throw an exception if not found. + /// Throws an exception if type is not a project class. + public static Guid GetClsid(ClsidContext context) + { + ValidateType(); + return Classes[typeof(T)].GetClsid(context); + } + + /// + /// Get IID corresponding to the COM object + /// + /// Projected class type + /// IID or throw an exception if not found. + /// Throws an exception if type is not a project class. + public static Guid? GetIid() + { + ValidateType(); + return Classes[typeof(T)].GetIid(); + } + + /// + /// Validate that the provided type is defined. + /// + /// Throws an exception if type is not a project class. + private static void ValidateType() + { + if (!Classes.ContainsKey(typeof(TType))) + { + throw new InvalidOperationException($"{typeof(TType).Name} is not a projected class type."); + } + } +} diff --git a/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClsidContext.cs b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClsidContext.cs new file mode 100644 index 00000000..f5283f3f --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/ClsidContext.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +public enum ClsidContext +{ + // Production CLSID Guids + Prod, + + // Development CLSID Guids + Dev, +} diff --git a/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerElevatedFactory.cs b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerElevatedFactory.cs new file mode 100644 index 00000000..5d16fd5b --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerElevatedFactory.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; +using WinRT; + +namespace GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +/// +/// Factory for creating winget COM objects using manual activation +/// to have them in an elevated context. +/// +/// +/// This needs to be called from an elevated context, or the winget +/// server will reject the connection. +/// +/// The WinGetServerManualActivation_CreateInstance function used here is defined in +/// https://github.com/microsoft/winget-cli/blob/master/src/WinGetServer/WinGetServerManualActivation_Client.cpp +/// +/// This class is based on what the winget cmdlets do. See +/// https://github.com/microsoft/winget-cli/blob/master/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs +/// +public partial class WindowsPackageManagerElevatedFactory : WindowsPackageManagerFactory +{ + // The only CLSID context supported by the DLL we call is Prod. + // If we want to use Dev classes we have to use a Dev version of the DLL. + public WindowsPackageManagerElevatedFactory() + : base(ClsidContext.Prod) + { + } + + protected override unsafe T CreateInstance(Guid clsid, Guid iid) + { + void* pUnknown = null; + + try + { + var hr = WinGetServerManualActivation_CreateInstance(in clsid, in iid, 0, out pUnknown); + Marshal.ThrowExceptionForHR(hr); + return MarshalInterface.FromAbi((IntPtr)pUnknown); + } + finally + { + // CoCreateInstance and FromAbi both AddRef on the native object. + // Release once to prevent memory leak. + if (pUnknown is not null) + { + Marshal.Release((IntPtr)pUnknown); + } + } + } + + [LibraryImport("winrtact.dll")] + private static unsafe partial int WinGetServerManualActivation_CreateInstance( + in Guid clsid, + in Guid iid, + uint flags, + out void* instance); +} diff --git a/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerFactory.cs b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerFactory.cs new file mode 100644 index 00000000..d3998ded --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerFactory.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using Microsoft.Management.Deployment; + +namespace GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +/// +/// Factory class for creating WinGet COM objects. +/// Details about each method can be found in the source IDL: +/// https://github.com/microsoft/winget-cli/blob/master/src/Microsoft.Management.Deployment/PackageManager.idl +/// +public abstract class WindowsPackageManagerFactory +{ + private readonly ClsidContext _clsidContext; + protected readonly bool _allowLowerTrustRegistration; + + public WindowsPackageManagerFactory(ClsidContext clsidContext, bool allowLowerTrustRegistration = false) + { + _clsidContext = clsidContext; + _allowLowerTrustRegistration = allowLowerTrustRegistration; + } + + /// + /// Creates an instance of the class . + /// + /// + /// Type must be one of the types defined in the winget COM API. + /// Implementations of this method can assume that and + /// are the right GUIDs for the class in the given context. + /// + protected abstract T CreateInstance(Guid clsid, Guid iid); + + public PackageManager CreatePackageManager() => CreateInstance(); + + public FindPackagesOptions CreateFindPackagesOptions() => CreateInstance(); + + public CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions() => CreateInstance(); + + public InstallOptions CreateInstallOptions() => CreateInstance(); + + public UninstallOptions CreateUninstallOptions() => CreateInstance(); + + public PackageMatchFilter CreatePackageMatchFilter() => CreateInstance(); + + /// + /// Creates an instance of the class . + /// + /// + /// This is a helper for calling the derived class's + /// method with the appropriate GUIDs. + /// + private T CreateInstance() + { + var clsid = ClassesDefinition.GetClsid(_clsidContext); + var iid = ClassesDefinition.GetIid(); + return CreateInstance(clsid, iid ?? Guid.Empty); + } +} diff --git a/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerStandardFactory.cs b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerStandardFactory.cs new file mode 100644 index 00000000..badb6233 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WindowsPackageManager/WindowsPackageManagerStandardFactory.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.System.Com; +using WinRT; + +namespace GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +public class WindowsPackageManagerStandardFactory : WindowsPackageManagerFactory +{ + public WindowsPackageManagerStandardFactory(ClsidContext clsidContext = ClsidContext.Prod, bool allowLowerTrustRegistration = false) + : base(clsidContext, allowLowerTrustRegistration) + { + } + + protected override T CreateInstance(Guid clsid, Guid iid) + { + var pUnknown = IntPtr.Zero; + try + { + var clsctx = CLSCTX.CLSCTX_LOCAL_SERVER; //CLSCTX.CLSCTX_ALL; + if (_allowLowerTrustRegistration) + { + clsctx |= CLSCTX.CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION; + } + + var hr = PInvoke.CoCreateInstance(clsid, pUnkOuter: null, clsctx, iid, out var result); + + // !! WARNING !! + // An exception may be thrown on the line below if this program + // runs as administrator and AllowLowerTrustRegistration settings is not checked + // or when WinGet is not installed on the system. + // It can be safely ignored if any of the conditions + // above are met. + Marshal.ThrowExceptionForHR(hr); + + pUnknown = Marshal.GetIUnknownForObject(result); + return MarshalGeneric.FromAbi(pUnknown); + } + finally + { + // CoCreateInstance and FromAbi both AddRef on the native object. + // Release once to prevent memory leak. + if (pUnknown != IntPtr.Zero) + { + Marshal.Release(pUnknown); + } + } + } +} diff --git a/src/GameCollector.PkgHandlers.Winget/WingetGame.cs b/src/GameCollector.PkgHandlers.Winget/WingetGame.cs new file mode 100644 index 00000000..39ff5a8d --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WingetGame.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using GameFinder.Common; +using JetBrains.Annotations; +using NexusMods.Paths; + +namespace GameCollector.PkgHandlers.Winget; + +/// +/// Represents an installed app or available package via Windows Package Manager. +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// + +[PublicAPI] +public record WingetGame(WingetGameId Id, + string? Name, + AbsolutePath InstallDirectory, + AbsolutePath Launch = new(), + string? InstallerUrl = "", + AbsolutePath Uninstall = new(), + bool IsInstalled = true, + bool IsOwned = true, + DateTime? InstallDate = null, + string? Description = "", + string? Publisher = "", + List? PackageTags = default, + string? PublisherUrl = "", + string? SupportUrl = "", + string? Homepage = "", + string? Author = "", + string? PackageName = "", + string? Moniker = "", + string? Source = "", + string? LicenseType = "", + string? InstalledVersion = "", + string? DefaultVersion = "", + string? AgeRating = "") : + GameData(Handler: Handler.PkgHandler_Winget, + GameId: Id.ToString(), + GameName: Name ?? "", + GamePath: InstallDirectory, + Launch: Launch, + LaunchUrl: InstallerUrl ?? "", + Icon: Launch, + Uninstall: Uninstall, + IsInstalled: IsInstalled, + IsOwned: IsOwned, + InstallDate: InstallDate, + Metadata: new Dictionary>(StringComparer.OrdinalIgnoreCase) + { + ["Description"] = new() { Description ?? "", }, + ["Developers"] = new() { Author ?? "", }, + ["Publishers"] = new() { Publisher ?? "", }, + ["Genres"] = PackageTags ?? new(), + ["WebInfo"] = new() { Homepage ?? PublisherUrl ?? "" }, + ["WebSupport"] = new() { SupportUrl ?? "" }, + ["PackageName"] = new() { PackageName ?? "" }, + ["Moniker"] = new() { Moniker ?? "", }, + ["Source"] = new() { Source ?? "", }, + ["License"] = new() { LicenseType ?? "", }, + ["InstalledVersion"] = new() { InstalledVersion ?? "", }, + ["DefaultVersion"] = new() { DefaultVersion ?? "", }, + ["AgeRating"] = new() { AgeRating ?? "", }, + }); diff --git a/src/GameCollector.PkgHandlers.Winget/WingetGameId.cs b/src/GameCollector.PkgHandlers.Winget/WingetGameId.cs new file mode 100644 index 00000000..315f8258 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WingetGameId.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using TransparentValueObjects; + +namespace GameCollector.PkgHandlers.Winget; + +/// +/// Represents an id for installed apps and available packages via Windows Package Manager. +/// +[ValueObject] +public readonly partial struct WingetGameId : IAugmentWith +{ + /// + public static IEqualityComparer InnerValueDefaultEqualityComparer { get; } = StringComparer.OrdinalIgnoreCase; +} + +/// +[PublicAPI] +public class WingetGameIdComparer : IEqualityComparer +{ + private static WingetGameIdComparer? _default; + + /// + /// Default equality comparer that uses . + /// + public static WingetGameIdComparer Default => _default ??= new(); + + private readonly StringComparison _stringComparison; + + /// + /// Default constructor that uses . + /// + public WingetGameIdComparer() : this(StringComparison.OrdinalIgnoreCase) { } + + /// + /// Constructor. + /// + /// + public WingetGameIdComparer(StringComparison stringComparison) + { + _stringComparison = stringComparison; + } + + /// + public bool Equals(WingetGameId x, WingetGameId y) => string.Equals(x.Value, y.Value, _stringComparison); + + /// + public int GetHashCode(WingetGameId obj) => obj.Value.GetHashCode(_stringComparison); +} diff --git a/src/GameCollector.PkgHandlers.Winget/WingetHandler.cs b/src/GameCollector.PkgHandlers.Winget/WingetHandler.cs new file mode 100644 index 00000000..1a2dfa15 --- /dev/null +++ b/src/GameCollector.PkgHandlers.Winget/WingetHandler.cs @@ -0,0 +1,878 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Security.Principal; +using System.Text; +using GameFinder.Common; +using GameFinder.RegistryUtils; +using JetBrains.Annotations; +using Microsoft.Extensions.Logging; +using Microsoft.Management.Deployment; +using NexusMods.Paths; +using OneOf; +using GameCollector.PkgHandlers.Winget.WindowsPackageManager; + +namespace GameCollector.PkgHandlers.Winget; + +/// +/// Handler for finding installed apps via Windows Package Manager. +/// +/// +/// Leverages winget, which inspects registry and WindowsApps (Microsoft Store) for installed programs. +/// +[PublicAPI] +public class WingetHandler : AHandler +{ + internal const string DefaultQuery = "game"; + internal const string UninstallRegKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall"; + + private readonly IRegistry _registry; + private readonly IFileSystem _fileSystem; + private ILogger? _logger; + + private WindowsPackageManagerFactory? _factory = null; + private static WindowsPackageManagerFactory? _externalFactory; + private PackageManager? _wingetManager; + private static PackageManager? _externalWingetManager; + private ProcessStartInfo _startInfo = new() + { + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + }; + + /// + /// Constructor. + /// + /// + /// The implementation of to use. For a shared instance + /// use on Windows. On Linux use null. + /// For tests either use , a custom implementation or just a mock + /// of the interface. + /// + /// + /// The implementation of to use. For a shared instance use + /// . For tests either use , + /// a custom implementation or just a mock of the interface. + /// + public WingetHandler(IRegistry registry, IFileSystem fileSystem, ILogger? logger = null) + { + _registry = registry; + _fileSystem = fileSystem; + _logger = logger; + + if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041, 0)) + { + // If the user is an administrator, use the elevated factory. Otherwhise COM will crash + if (new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)) + _factory = new WindowsPackageManagerElevatedFactory(); + //_factory = new WindowsPackageManagerStandardFactory(allowLowerTrustRegistration: true); + else + _factory = new WindowsPackageManagerStandardFactory(); + + // Create Package Manager and get available catalogs + _wingetManager = _factory?.CreatePackageManager(); + _externalFactory = _factory; + _externalWingetManager = _wingetManager; + } + } + + /// + public override IEqualityComparer? IdEqualityComparer => WingetGameIdComparer.Default; + + /// + public override Func IdSelector => game => game.Id; + + /// + public override AbsolutePath FindClient() + { + // Not necessary if using API + var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var wingetExe = _fileSystem.FromUnsanitizedFullPath(Path.Combine(localAppData, "Microsoft", "WindowsApps", "winget.exe")); + if (Path.IsPathRooted(localAppData) && _fileSystem.FileExists(wingetExe)) + return wingetExe; + + return default; + } + + /// + public override IEnumerable> FindAllGames(Settings? settings = null) + { + return FindAllGames(settings?.InstalledOnly ?? false, settings?.OwnedOnly ?? false, settings?.GamesOnly ?? false); + } + + /// + /// Finds all apps supported by this package handler. The return type + /// will always be a non-null game or a non-null error message. + /// + /// + /// + /// + /// + /// Get additional information about winget/msstore packages + /// + public IEnumerable> FindAllGames( + bool installedOnly = false, + bool ownedOnly = false, + bool gamesOnly = false, + string? query = DefaultQuery, + bool expandPackage = false) + { + //_logger?.LogDebug("***FindAllGames()"); + if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041, 0)) + { + //_logger?.LogDebug("***Only supported on Windows 10.0.19041.0 or later."); + yield return new ErrorMessage("Only supported on Windows 10.0.19041.0 or later."); + yield break; + } + if (_wingetManager is null) + { + //_logger?.LogDebug("***Could not access Windows Package Manager."); + yield return new ErrorMessage("Could not access Windows Package Manager."); + yield break; + } + + Dictionary> items = new(); + + if (!ownedOnly) + items = GetInstalled(); + + if (!installedOnly && !string.IsNullOrEmpty(query)) + { + foreach (var game in SearchFreeGames(query, expandPackage)) + { + items.TryAdd(game.Key, game.Value); + } + } + + foreach (var item in items) + { + //_logger?.LogDebug("***" + item.Value.ToString()); + yield return item.Value; + } + } + + private Dictionary> GetInstalled() + { + //_logger?.LogDebug("***GetInstalled()"); + if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041, 0)) + { + return new() { [WingetGameId.From("")] = new ErrorMessage("Only supported on Windows 10.0.19041.0 or later.") }; + } + if (_wingetManager is null || _factory is null) + { + return new() { [WingetGameId.From("")] = new ErrorMessage("Could not access Windows Package Manager.") }; + } + + Dictionary> installed = new(); + + // CHANGE THIS INDEX TO CHANGE THE SOURCE + var selectedIndex = 0; // TODO: I suspect this refers to winget vs. msstore + + PackageCatalogReference installedSearchCatalogRef; + if (selectedIndex < 0) + { + installedSearchCatalogRef = _wingetManager.GetLocalPackageCatalog(LocalPackageCatalog.InstalledPackages); + } + else + { + var selectedRemoteCatalogRef = _wingetManager.GetPackageCatalogs().ToArray()[selectedIndex]; + + //_logger?.LogDebug($"***Searching on package catalog {selectedRemoteCatalogRef.Info.Name} "); + + var createCompositePackageCatalogOptions = _factory.CreateCreateCompositePackageCatalogOptions(); + createCompositePackageCatalogOptions.Catalogs.Add(selectedRemoteCatalogRef); + createCompositePackageCatalogOptions.CompositeSearchBehavior = CompositeSearchBehavior.LocalCatalogs; + installedSearchCatalogRef = _wingetManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions); + } + + var connectResult = installedSearchCatalogRef.Connect(); + if (connectResult.Status != ConnectResultStatus.Ok) + { + //_logger?.LogDebug("***Failed to connect to local catalog."); + return new() { [WingetGameId.From("")] = new ErrorMessage("Failed to connect to local catalog.") }; + } + + var findPackagesOptions = _factory.CreateFindPackagesOptions(); + var filter = _factory.CreatePackageMatchFilter(); + filter.Field = PackageMatchField.Id; + filter.Option = PackageFieldMatchOption.ContainsCaseInsensitive; + filter.Value = ""; + findPackagesOptions.Filters.Add(filter); + + var taskResult = connectResult.PackageCatalog.FindPackages(findPackagesOptions); + + // Begin enumeration + foreach (var match in taskResult.Matches.ToArray()) + { + var pkg = match.CatalogPackage; + if (pkg is null) + continue; + + installed.TryAdd(WingetGameId.From(pkg.Id), new WingetGame( + Id: WingetGameId.From(pkg.Id), + Name: pkg.Name, + InstallDirectory: default, + IsInstalled: pkg.DefaultInstallVersion != null, + IsOwned: pkg.DefaultInstallVersion != null, + //PackageTags: pkg.Tags???, + Source: pkg.DefaultInstallVersion?.Channel, // is this winget vs. msstore? + PackageName: pkg.DefaultInstallVersion?.PackageCatalog.Info.Name, + //ProductCodes: pkg.DefaultInstallVersion?.ProductCodes.ToList(), + Publisher: pkg.InstalledVersion.Publisher, + InstalledVersion: pkg.InstalledVersion.DisplayName, + DefaultVersion: pkg.DefaultInstallVersion?.DisplayName)); + } + return installed; + } + + private Dictionary> GetInstalledParse(bool expandPackage) + { + //_logger?.LogDebug("***GetInstalledParse()"); +#if DEBUG + Console.OutputEncoding = Encoding.UTF8; +#endif + + Dictionary> installed = new(); + + var wingetExe = FindClient(); + if (wingetExe == default) + { + //_logger?.LogDebug("***Winget not installed"); + return new() { [WingetGameId.From("")] = new ErrorMessage("Winget not installed") }; + } +#if DEBUG + Console.WriteLine("wingetExe: " + wingetExe.GetFullPath()); +#endif + + using var process = new Process(); + process.StartInfo = _startInfo; + process.StartInfo.FileName = wingetExe.GetFullPath(); + process.StartInfo.Arguments = "list --nowarn --disable-interactivity"; + process.StartInfo.StandardOutputEncoding = Encoding.UTF8; + process.StartInfo.StandardErrorEncoding = Encoding.UTF8; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + if (string.IsNullOrEmpty(output)) + { + //_logger?.LogDebug("***No output from winget"); + return new() { [WingetGameId.From("")] = new ErrorMessage("No output from winget") }; + } +#if DEBUG + Console.WriteLine("[" + output + "]"); +#endif + + List colPos = new(); + var i = 0; + foreach (var line in output.Split('\n')) + { + if (i == 0) + { + if (!line.Contains("Name ", StringComparison.Ordinal)) + continue; + + var headLine = line[line.IndexOf("Name ", StringComparison.Ordinal)..]; + foreach (var col in headLine.Split(' ', StringSplitOptions.RemoveEmptyEntries)) + { + var c = headLine.IndexOf(col, StringComparison.Ordinal); + if (c > -1) + colPos.Add(c); + } + if (colPos.Count < 5) + break; + } + else if (i > 1 && !string.IsNullOrWhiteSpace(line)) // skip separator line + { + string name = "", strId = "", version = "", available = ""; + string? source = null; + WingetGameId id = default; + // TODO: This doesn't work if there are surrogate pairs in the string + if (line.Length > colPos[1]) + name = line[colPos[0]..colPos[1]].Trim(); + if (line.Length > colPos[2]) + { + strId = line[colPos[1]..colPos[2]].Trim(); + id = WingetGameId.From(strId); + } + if (line.Length > colPos[3]) + version = line[colPos[2]..colPos[3]].Trim(); + if (line.Length > colPos[4]) + { + available = line[colPos[3]..colPos[4]].Trim(); + source = line[colPos[4]..].Trim(); + } + + if (string.IsNullOrWhiteSpace(source)) // non-package install + { + if (!expandPackage) + { + if (installed.TryAdd(id, new WingetGame( + Id: id, + Name: name, + InstallDirectory: default, + IsInstalled: true, + IsOwned: true, + InstalledVersion: version))) + { + //_logger?.LogDebug(" " + name); + } + i++; + continue; + } + + if (name.EndsWith('…') || strId.EndsWith('…') || version.EndsWith('…')) + { + (name, strId, version) = Relist(name, strId, version, source); + strId = strId.TrimEnd('…'); + id = WingetGameId.From(strId); + } + + if (!string.IsNullOrEmpty(strId) && + strId.StartsWith(@"ARP\", StringComparison.Ordinal) && + !strId.EndsWith('…')) + { + var game = ParseRegistry(strId); + if (game.IsT0) + { + if (installed.TryAdd(id, new WingetGame( + Id: id, + Name: name, + InstallDirectory: game.AsT0.InstallDirectory, + Launch: game.AsT0.Launch, + Uninstall: game.AsT0.Uninstall, + IsInstalled: true, + IsOwned: true, + InstallDate: game.AsT0.InstallDate, + Publisher: game.AsT0.Publisher, + SupportUrl: game.AsT0.SupportUrl, + Homepage: game.AsT0.Homepage, + InstalledVersion: version))) + { + //_logger?.LogDebug("@ " + name); + } + i++; + continue; + } + + if (installed.TryAdd(id, game.AsT1)) + { + //_logger?.LogDebug("***" + game.AsT1.Message); + } + i++; + } + + if (installed.TryAdd(id, new WingetGame( + Id: id, + Name: name, + InstallDirectory: default, + IsInstalled: true, + IsOwned: true, + InstalledVersion: version))) + { + //_logger?.LogDebug("? " + name); + } + i++; + continue; + } + + //else [package install] + + if (!expandPackage) + { + if (name.EndsWith('…') || strId.EndsWith('…') || version.EndsWith('…')) + { + (name, strId, version) = Relist(name, strId, version, source); + strId = strId.TrimEnd('…'); + id = WingetGameId.From(strId); + } + + if (installed.TryAdd(id, new WingetGame( + Id: id, + Name: name, + InstallDirectory: default, + IsInstalled: true, + IsOwned: true, + Source: source, + InstalledVersion: version, + DefaultVersion: available))) + { + //_logger?.LogDebug(" " + name); + } + i++; + continue; + } + + if (strId.EndsWith('…')) + { + (name, strId, version) = Relist(name, strId, version, source); + strId = strId.TrimEnd('…'); + id = WingetGameId.From(strId); + } + if (installed.TryAdd(id, GetPackageInfo(colPos, line, search: false))) + { + //_logger?.LogDebug(" " + name); + } + } + + i++; + } + //_logger?.LogDebug("GetInstalledParse(): " + i + " apps"); + + return installed; + } + + private (string, string, string) Relist(string name, string id, string version, string? source = null) + { + //_logger?.LogDebug("***Relist()"); + if (string.IsNullOrWhiteSpace(source)) + source = "winget"; + + using var process = new Process(); + process.StartInfo = _startInfo; + process.StartInfo.FileName = FindClient().GetFullPath(); + //process.StartInfo.Arguments = $"list --name \"{name.TrimEnd('…')}\" --source {source} --nowarn --disable-interactivity"; + process.StartInfo.Arguments = $"list --id \"{id.TrimEnd('…')}\" --source {source} --nowarn --disable-interactivity"; + process.Start(); + var listOutput = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + List listCols = new(); + var i = 0; + foreach (var listLine in listOutput.Split('\n')) + { + if (i == 0) + { + if (!listLine.Contains("Name", StringComparison.Ordinal)) + continue; + + var headLine = listLine[listLine.IndexOf("Name ", StringComparison.Ordinal)..]; + foreach (var col in headLine.Split(' ', StringSplitOptions.RemoveEmptyEntries)) + { + var c = headLine.IndexOf(col, StringComparison.Ordinal); + if (c > -1) + listCols.Add(c); + } + if (listCols.Count < 3) + break; + } + else if (i > 1 && !string.IsNullOrWhiteSpace(listLine)) // skip separator line + { + // TODO: This doesn't work if there are UTF-16 surrogate pairs in the string + if (listLine.Length > listCols[1]) + name = listLine[listCols[0]..listCols[1]].Trim(); + if (listLine.Length > listCols[2]) + { + id = listLine[listCols[1]..listCols[2]].Trim(); + version = listLine[listCols[2]..].Trim(); + } + } + + i++; + } + + return (name, id, version); + } + + private Dictionary> SearchFreeGames(string query = DefaultQuery, bool expandPackage = false) + { + //_logger?.LogDebug("***SearchFreeGames()"); + if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041, 0)) + { + return new() { [WingetGameId.From("")] = new ErrorMessage("Only supported on Windows 10.0.19041.0 or later.") }; + } + if (_wingetManager is null || _factory is null) + { + return new() { [WingetGameId.From("")] = new ErrorMessage("Could not access Windows Package Manager.") }; + } + + Dictionary> freeGames = new(); + var availableCatalogs = _wingetManager.GetPackageCatalogs(); + + foreach (var catalog in availableCatalogs.ToArray()) + { + // Create a filter to search for packages with query ["game" default] + var filterList = _factory.CreateFindPackagesOptions(); + + // Add the query to the filter + var tagFilter = _factory.CreatePackageMatchFilter(); + tagFilter.Field = PackageMatchField.Tag; + tagFilter.Value = query; + filterList.Filters.Add(tagFilter); + + // Find the packages with the filters + //var searchResults = await catalog.ConnectAsync().GetResults().PackageCatalog.FindPackagesAsync(filterList); + var searchResults = catalog.Connect().PackageCatalog.FindPackages(filterList); + foreach (var match in searchResults.Matches.ToArray()) + { + var pkg = match.CatalogPackage; + var id = WingetGameId.From(pkg.Id); + + freeGames.Add(id, new WingetGame( + Id: id, + Name: pkg.Name, + InstallDirectory: default, + PackageTags: pkg.DefaultInstallVersion.PackageFamilyNames.ToList(), + Publisher: pkg.DefaultInstallVersion.Publisher, + Source: pkg.DefaultInstallVersion.Channel, + DefaultVersion: pkg.DefaultInstallVersion.DisplayName + )); + + //_logger?.LogDebug("* " + pkg.Name); + } + } + + return new(); + } + + private Dictionary> SearchFreeGamesParse(string query = DefaultQuery, bool expandPackage = false) + { + //_logger?.LogDebug("***SearchFreeGamesParse()"); + Dictionary> freeGames = new(); + + using var process = new Process(); + process.StartInfo = _startInfo; + process.StartInfo.FileName = FindClient().GetFullPath(); + process.StartInfo.Arguments = $"search --tag {query} --source winget --nowarn --disable-interactivity"; + process.StartInfo.StandardOutputEncoding = Encoding.UTF8; + process.StartInfo.StandardErrorEncoding = Encoding.UTF8; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + if (string.IsNullOrEmpty(output)) + { + //_logger?.LogDebug("***No output from winget"); + return new() { [WingetGameId.From("")] = new ErrorMessage("No output from winget") }; + } + + List colPos = new(); + var i = 0; + foreach (var line in output.Split('\n')) + { + if (i == 0) + { + if (!line.Contains("Name ", StringComparison.Ordinal)) + continue; + + var headLine = line[line.IndexOf("Name ", StringComparison.Ordinal)..]; + foreach (var col in headLine.Split(' ', StringSplitOptions.RemoveEmptyEntries)) + { + var c = headLine.IndexOf(col, StringComparison.Ordinal); + if (c > -1) + colPos.Add(c); + } + if (colPos.Count < 5) + break; + } + else if (i > 1 && !string.IsNullOrWhiteSpace(line)) // skip separator line + { + string name = "", strId = "", available = "", match = ""; + string? source = null; + WingetGameId id = default; + // TODO: This doesn't work if there are UTF-16 surrogate pairs in the string + if (line.Length > colPos[1]) + name = line[colPos[0]..colPos[1]].Trim(); + if (line.Length > colPos[2]) + { + strId = line[colPos[1]..colPos[2]].Trim(); + id = WingetGameId.From(strId); + } + if (line.Length > colPos[3]) + available = line[colPos[2]..colPos[3]].Trim(); + if (line.Length > colPos[4]) + { + match = line[colPos[3]..colPos[4]].Trim(); + source = line[colPos[4]..].Trim(); + } + + if (!expandPackage) + { + if (freeGames.TryAdd(id, new WingetGame( + Id: id, + Name: name, + InstallDirectory: default, + IsInstalled: false, + IsOwned: false, + DefaultVersion: available))) + { + //_logger?.LogDebug("* " + name); + i++; + } + continue; + } + + if (freeGames.TryAdd(id, GetPackageInfo(colPos, line, search: true))) + { + //_logger?.LogDebug("*@" + name); + } + } + + i++; + } + //_logger?.LogDebug("SearchFreeGamesParse(): " + i + " games"); + + return freeGames; + } + + private OneOf ParseRegistry(string id) + { + //_logger?.LogDebug("***ParseRegistry()"); + // id syntax = "ARP\[Machine|User]\[X64|X86]\ + + string? regKeyName; // = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"; + IRegistryKey baseKey; // = _registry.OpenBaseKey(RegistryHive.LocalMachine); + if (id.StartsWith(@"ARP\Machine\X64\", StringComparison.Ordinal)) + { + regKeyName = UninstallRegKey + id[@"ARP\Machine\X64\".Length..]; + baseKey = _registry.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); + } + else if (id.StartsWith(@"ARP\Machine\X86\", StringComparison.Ordinal)) + { + regKeyName = UninstallRegKey + id[@"ARP\Machine\X86\".Length..]; + baseKey = _registry.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32); + } + else if (id.StartsWith(@"ARP\User\X64\", StringComparison.Ordinal)) + { + regKeyName = UninstallRegKey + id[@"ARP\User\X64\".Length..]; + baseKey = _registry.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); + } + else if (id.StartsWith(@"ARP\User\X86\", StringComparison.Ordinal)) + { + regKeyName = UninstallRegKey + id[@"ARP\User\X86\".Length..]; + baseKey = _registry.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32); + } + else + return new ErrorMessage("Did not find expected \"ARP\\[Machine|User]\\[X64|X86]\\\" registry key prefix in id " + id); + + try + { + using var regKey = baseKey.OpenSubKey(regKeyName); + if (regKey is null) + { + return new ErrorMessage($"Unable to open {regKeyName}"); + } + + DateTime installDate = default; + + regKey.TryGetString("DisplayIcon", out var launch); + regKey.TryGetString("DisplayName", out var name); + regKey.TryGetString("HelpLink", out var help); + if (regKey.TryGetString("InstallDate", out var date)) + DateTime.TryParseExact(date, "yyyyMMdd", new CultureInfo("en-US"), DateTimeStyles.None, out installDate); + regKey.TryGetString("InstallLocation", out var path); + regKey.TryGetString("Publisher", out var pub); + regKey.TryGetString("UninstallString", out var uninst); + regKey.TryGetString("URLInfoAbout", out var url); + + return new WingetGame( + Id: WingetGameId.From(id), + Name: name, + InstallDirectory: Path.IsPathRooted(path) ? _fileSystem.FromUnsanitizedFullPath(path) : new(), + InstallDate: installDate == default ? null : installDate, + Launch: Path.IsPathRooted(launch) ? _fileSystem.FromUnsanitizedFullPath(launch) : new(), + Uninstall: Path.IsPathRooted(uninst) ? _fileSystem.FromUnsanitizedFullPath(uninst) : new(), + Publisher: pub, + SupportUrl: help, + Homepage: url + ); + } + catch (Exception e) + { + return new ErrorMessage(e, $"Exception while parsing registry key {regKeyName}"); + } + } + + private OneOf GetPackageInfo(List colPos, string listInfo, bool search = false) + { + //_logger?.LogDebug("***GetPackageInfo()"); + //list header = "Name,Id,Version,Available,Source" + //search header = "Name,Id,Version,Match,Source" + + var isDescription = false; + //var isReleaseNotes = false; + var isTags = false; + + var name = listInfo[colPos[0]..colPos[1]].Trim(); + var strId = listInfo[colPos[1]..colPos[2]].Trim(); + var id = WingetGameId.From(strId); + var version = ""; + + string? available; + //string? match; + if (search) + { + available = listInfo[colPos[2]..colPos[3]].Trim(); + //match = listInfo[colPos[3]..colPos[4]].Trim(); + } + else + { + version = listInfo[colPos[2]..colPos[3]].Trim(); + available = listInfo[colPos[3]..colPos[4]].Trim(); + } + var source = listInfo[colPos[4]..].Trim(); + + if (strId.EndsWith('…')) + { + (name, strId, version) = Relist(name, strId, version); + id = WingetGameId.From(strId); + } + + var pkgName = ""; + var publisher = ""; + //var publisherUrl = ""; + var publisherSupportUrl = ""; + var author = ""; + var moniker = ""; + var description = ""; + var homepage = ""; + var license = ""; + //var licenseUrl = ""; + //var privacyUrl = ""; + //var copyright = ""; + //var releaseNotes = ""; + //var releaseNotesUrl = ""; + //var purchaseUrl = ""; + //var documentationTutorials = ""; + //var documentationManual = ""; + List tags = new(); + //var agreementsCategory = ""; + //var agreementsPricing = ""; + //string agreementsFreeTrial = ""; + var agreementsAgeRatings = ""; + //string agreementsTermsOfTransaction = ""; + //string agreementsSeizureWarning = ""; + //string agreementsStoreLicenseTerms = ""; + //var installerType = ""; + //var installerLocale = ""; + var installerUrl = ""; + //var installerSha256 = ""; + //var installerStoreProductId = ""; + //var installerReleaseDate = ""; + //var installerOfflineDistributionSupported = false; + + using var process = new Process(); + process.StartInfo = _startInfo; + process.StartInfo.FileName = FindClient().GetFullPath(); + process.StartInfo.Arguments = $"show {strId} --nowarn --disable-interactivity"; + process.Start(); + var pkgOutput = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + var i = 0; + foreach (var pkgLine in pkgOutput.Split('\n')) + { + if (isDescription) + { + if (pkgLine.StartsWith(' ')) + { + description += pkgLine.TrimStart(); + continue; + } + isDescription = false; + } + /* + if (isReleaseNotes) + { + if (pkgLine.StartsWith(' ')) + { + releaseNotes += pkgLine.TrimStart(); + continue; + } + isReleaseNotes = false; + } + */ + if (isTags) + { + if (pkgLine.StartsWith(' ')) + { + tags.Add(pkgLine.TrimStart()); + continue; + } + isTags = false; + } + + if (i == 0) + { + if (pkgLine.Contains("Found ", StringComparison.Ordinal)) + { + var headLine = pkgLine[pkgLine.IndexOf("Found ", StringComparison.Ordinal)..]; + if (headLine.LastIndexOf('[') > 7) + { + strId = headLine[(headLine.LastIndexOf('[') + 1)..^2]; + id = WingetGameId.From(strId); + pkgName = headLine["Found ".Length..headLine.LastIndexOf('[')]; + } + else + pkgName = headLine["Found ".Length..]; + } + else + continue; + } + else if (pkgLine.StartsWith("Version: ", StringComparison.Ordinal)) + version = pkgLine["Version: ".Length..]; + else if (pkgLine.StartsWith("Publisher: ", StringComparison.Ordinal)) + publisher = pkgLine["Publisher: ".Length..]; + else if (pkgLine.StartsWith("Publisher Support Url: ", StringComparison.Ordinal)) + publisherSupportUrl = pkgLine["Publisher Support Url: ".Length..]; + else if (pkgLine.StartsWith("Moniker: ", StringComparison.Ordinal)) + moniker = pkgLine["Moniker: ".Length..]; + else if (pkgLine.StartsWith("Description:", StringComparison.Ordinal)) + { + description = pkgLine["Description:".Length..].TrimStart(); + isDescription = true; + } + else if (pkgLine.StartsWith("Homepage: ", StringComparison.Ordinal)) + homepage = pkgLine["Homepage: ".Length..]; + else if (pkgLine.StartsWith("License: ", StringComparison.Ordinal)) + license = pkgLine["License: ".Length..]; + //else if (pkgLine.StartsWith("Release Notes:", StringComparison.Ordinal)) + //{ + // releaseNotes = pkgLine["Release Notes:".Length..].TrimStart(); + // isReleaseNotes = true; + //} + else if (pkgLine.StartsWith(" Age Ratings: ", StringComparison.Ordinal)) + agreementsAgeRatings = pkgLine[" Age Ratings: ".Length..]; + else if (pkgLine.StartsWith("Tags:", StringComparison.Ordinal)) + isTags = true; + else if (pkgLine.StartsWith(" Installer Url: ", StringComparison.Ordinal)) + installerUrl = pkgLine[" Installer Url: ".Length..]; + + i++; + } + + //_logger?.LogDebug("> " + name); + return new WingetGame( + Id: id, + Name: name, + InstallDirectory: default, + InstallerUrl: installerUrl, + IsInstalled: true, + IsOwned: true, + Description: description, + Publisher: publisher, + Author: author, + PackageTags: tags, + Homepage: homepage, + SupportUrl: publisherSupportUrl, + PackageName: pkgName, + Moniker: moniker, + Source: source, + LicenseType: license, + InstalledVersion: version, + DefaultVersion: available, + AgeRating: agreementsAgeRatings); + } +} diff --git a/src/GameCollector.SQLiteUtils/GameCollector.SQLiteUtils.csproj b/src/GameCollector.SQLiteUtils/GameCollector.SQLiteUtils.csproj index 45a238ab..8f668c8b 100644 --- a/src/GameCollector.SQLiteUtils/GameCollector.SQLiteUtils.csproj +++ b/src/GameCollector.SQLiteUtils/GameCollector.SQLiteUtils.csproj @@ -1,5 +1,9 @@ + + AnyCPU;x64 + + diff --git a/src/GameCollector.StoreHandlers.Amazon/GameCollector.StoreHandlers.Amazon.csproj b/src/GameCollector.StoreHandlers.Amazon/GameCollector.StoreHandlers.Amazon.csproj index 991f937a..3c8c0557 100644 --- a/src/GameCollector.StoreHandlers.Amazon/GameCollector.StoreHandlers.Amazon.csproj +++ b/src/GameCollector.StoreHandlers.Amazon/GameCollector.StoreHandlers.Amazon.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with Amazon Games. amazon amazon-games games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Arc/GameCollector.StoreHandlers.Arc.csproj b/src/GameCollector.StoreHandlers.Arc/GameCollector.StoreHandlers.Arc.csproj index 63d45077..b9ed0f92 100644 --- a/src/GameCollector.StoreHandlers.Arc/GameCollector.StoreHandlers.Arc.csproj +++ b/src/GameCollector.StoreHandlers.Arc/GameCollector.StoreHandlers.Arc.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Arc. arc games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.BattleNet/GameCollector.StoreHandlers.BattleNet.csproj b/src/GameCollector.StoreHandlers.BattleNet/GameCollector.StoreHandlers.BattleNet.csproj index 5bb06715..da27e469 100644 --- a/src/GameCollector.StoreHandlers.BattleNet/GameCollector.StoreHandlers.BattleNet.csproj +++ b/src/GameCollector.StoreHandlers.BattleNet/GameCollector.StoreHandlers.BattleNet.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Blizzard Battle.net. battlenet battle-net blizzard games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.BigFish/GameCollector.StoreHandlers.BigFish.csproj b/src/GameCollector.StoreHandlers.BigFish/GameCollector.StoreHandlers.BigFish.csproj index e6872e13..d8418916 100644 --- a/src/GameCollector.StoreHandlers.BigFish/GameCollector.StoreHandlers.BigFish.csproj +++ b/src/GameCollector.StoreHandlers.BigFish/GameCollector.StoreHandlers.BigFish.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with Big Fish Game Manager. bigfish big-fish games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.GameJolt/GameCollector.StoreHandlers.GameJolt.csproj b/src/GameCollector.StoreHandlers.GameJolt/GameCollector.StoreHandlers.GameJolt.csproj index 81416a37..68c78bd1 100644 --- a/src/GameCollector.StoreHandlers.GameJolt/GameCollector.StoreHandlers.GameJolt.csproj +++ b/src/GameCollector.StoreHandlers.GameJolt/GameCollector.StoreHandlers.GameJolt.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Game Jolt Client. gamejolt game-jolt games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Humble/GameCollector.StoreHandlers.Humble.csproj b/src/GameCollector.StoreHandlers.Humble/GameCollector.StoreHandlers.Humble.csproj index f0a8c0d1..400cd186 100644 --- a/src/GameCollector.StoreHandlers.Humble/GameCollector.StoreHandlers.Humble.csproj +++ b/src/GameCollector.StoreHandlers.Humble/GameCollector.StoreHandlers.Humble.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with the Humble App. humble humblebundle humble-bundle games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.IGClient/GameCollector.StoreHandlers.IGClient.csproj b/src/GameCollector.StoreHandlers.IGClient/GameCollector.StoreHandlers.IGClient.csproj index 3f1e16d7..d3442f33 100644 --- a/src/GameCollector.StoreHandlers.IGClient/GameCollector.StoreHandlers.IGClient.csproj +++ b/src/GameCollector.StoreHandlers.IGClient/GameCollector.StoreHandlers.IGClient.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with the Indiegala Client. igclient galaclient indiegala indiegala-client games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Itch/GameCollector.StoreHandlers.Itch.csproj b/src/GameCollector.StoreHandlers.Itch/GameCollector.StoreHandlers.Itch.csproj index 19a44207..6e263355 100644 --- a/src/GameCollector.StoreHandlers.Itch/GameCollector.StoreHandlers.Itch.csproj +++ b/src/GameCollector.StoreHandlers.Itch/GameCollector.StoreHandlers.Itch.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with itch. itch games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Legacy/GameCollector.StoreHandlers.Legacy.csproj b/src/GameCollector.StoreHandlers.Legacy/GameCollector.StoreHandlers.Legacy.csproj index 3a23da74..988844d4 100644 --- a/src/GameCollector.StoreHandlers.Legacy/GameCollector.StoreHandlers.Legacy.csproj +++ b/src/GameCollector.StoreHandlers.Legacy/GameCollector.StoreHandlers.Legacy.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Legacy Games Launcher. legacy legacy-games games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Oculus/GameCollector.StoreHandlers.Oculus.csproj b/src/GameCollector.StoreHandlers.Oculus/GameCollector.StoreHandlers.Oculus.csproj index 07877f55..ac237a9c 100644 --- a/src/GameCollector.StoreHandlers.Oculus/GameCollector.StoreHandlers.Oculus.csproj +++ b/src/GameCollector.StoreHandlers.Oculus/GameCollector.StoreHandlers.Oculus.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Oculus. oculus meta oculus-rift oculus-quest meta-quest games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Paradox/GameCollector.StoreHandlers.Paradox.csproj b/src/GameCollector.StoreHandlers.Paradox/GameCollector.StoreHandlers.Paradox.csproj index d65948da..6aa388d6 100644 --- a/src/GameCollector.StoreHandlers.Paradox/GameCollector.StoreHandlers.Paradox.csproj +++ b/src/GameCollector.StoreHandlers.Paradox/GameCollector.StoreHandlers.Paradox.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with Paradox Launcher. paradox games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Plarium/GameCollector.StoreHandlers.Plarium.csproj b/src/GameCollector.StoreHandlers.Plarium/GameCollector.StoreHandlers.Plarium.csproj index b2d059dd..e56a2745 100644 --- a/src/GameCollector.StoreHandlers.Plarium/GameCollector.StoreHandlers.Plarium.csproj +++ b/src/GameCollector.StoreHandlers.Plarium/GameCollector.StoreHandlers.Plarium.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Plarium Play. plarium plarium-play games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Riot/GameCollector.StoreHandlers.Riot.csproj b/src/GameCollector.StoreHandlers.Riot/GameCollector.StoreHandlers.Riot.csproj index 1c4c60b3..52c2fb81 100644 --- a/src/GameCollector.StoreHandlers.Riot/GameCollector.StoreHandlers.Riot.csproj +++ b/src/GameCollector.StoreHandlers.Riot/GameCollector.StoreHandlers.Riot.csproj @@ -2,6 +2,7 @@ Library for finding games installed with the Riot Client. riot riot-client games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.RobotCache/GameCollector.StoreHandlers.RobotCache.csproj b/src/GameCollector.StoreHandlers.RobotCache/GameCollector.StoreHandlers.RobotCache.csproj index 52d70456..04b42ed1 100644 --- a/src/GameCollector.StoreHandlers.RobotCache/GameCollector.StoreHandlers.RobotCache.csproj +++ b/src/GameCollector.StoreHandlers.RobotCache/GameCollector.StoreHandlers.RobotCache.csproj @@ -2,6 +2,7 @@ Library for finding games installed with the Robot Cache Client. robotcache robot-cache games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Rockstar/GameCollector.StoreHandlers.Rockstar.csproj b/src/GameCollector.StoreHandlers.Rockstar/GameCollector.StoreHandlers.Rockstar.csproj index 3a205661..b10006d4 100644 --- a/src/GameCollector.StoreHandlers.Rockstar/GameCollector.StoreHandlers.Rockstar.csproj +++ b/src/GameCollector.StoreHandlers.Rockstar/GameCollector.StoreHandlers.Rockstar.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Rockstar Games Launcher. rockstar games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.Ubisoft/GameCollector.StoreHandlers.Ubisoft.csproj b/src/GameCollector.StoreHandlers.Ubisoft/GameCollector.StoreHandlers.Ubisoft.csproj index d345bb9b..fc802fa8 100644 --- a/src/GameCollector.StoreHandlers.Ubisoft/GameCollector.StoreHandlers.Ubisoft.csproj +++ b/src/GameCollector.StoreHandlers.Ubisoft/GameCollector.StoreHandlers.Ubisoft.csproj @@ -2,6 +2,7 @@ Library for finding games owned and installed with Ubisoft Connect. ubisoft ubisoft-connect uplay games + AnyCPU;x64 diff --git a/src/GameCollector.StoreHandlers.WargamingNet/GameCollector.StoreHandlers.WargamingNet.csproj b/src/GameCollector.StoreHandlers.WargamingNet/GameCollector.StoreHandlers.WargamingNet.csproj index efde6f96..cfe453e2 100644 --- a/src/GameCollector.StoreHandlers.WargamingNet/GameCollector.StoreHandlers.WargamingNet.csproj +++ b/src/GameCollector.StoreHandlers.WargamingNet/GameCollector.StoreHandlers.WargamingNet.csproj @@ -2,6 +2,7 @@ Library for finding games installed with Wargaming.Net Game Center. wargaming wargaming-net games + AnyCPU;x64 diff --git a/src/GameCollector.YamlUtils/GameCollector.YamlUtils.csproj b/src/GameCollector.YamlUtils/GameCollector.YamlUtils.csproj index 76616889..27778008 100644 --- a/src/GameCollector.YamlUtils/GameCollector.YamlUtils.csproj +++ b/src/GameCollector.YamlUtils/GameCollector.YamlUtils.csproj @@ -1,5 +1,9 @@ + + AnyCPU;x64 + + diff --git a/src/GameFinder.Common/GameFinder.Common.csproj b/src/GameFinder.Common/GameFinder.Common.csproj index b371ba65..7fc9f30c 100644 --- a/src/GameFinder.Common/GameFinder.Common.csproj +++ b/src/GameFinder.Common/GameFinder.Common.csproj @@ -1,6 +1,7 @@ GameCollector.GameFinderCommon + AnyCPU;x64 diff --git a/src/GameFinder.Common/Handler.cs b/src/GameFinder.Common/Handler.cs index d7953b7c..e89b1e06 100644 --- a/src/GameFinder.Common/Handler.cs +++ b/src/GameFinder.Common/Handler.cs @@ -144,6 +144,11 @@ public enum Handler [Description("GameCollector.EmuHandlers.MAME")] EmuHandler_MAME, /// + /// Windows Package Manager package handler + /// + [Description("GameCollector.PkgHandlers.Winget")] + PkgHandler_Winget, + /// /// TheGamesDb.net data handler /// [Description("GameCollector.DataHandlers.TheGamesDb")] diff --git a/src/GameFinder.Launcher.Heroic/GameFinder.Launcher.Heroic.csproj b/src/GameFinder.Launcher.Heroic/GameFinder.Launcher.Heroic.csproj index 2404fc86..522743bd 100644 --- a/src/GameFinder.Launcher.Heroic/GameFinder.Launcher.Heroic.csproj +++ b/src/GameFinder.Launcher.Heroic/GameFinder.Launcher.Heroic.csproj @@ -1,9 +1,10 @@ - + GameCollector.Launcher.Heroic false + AnyCPU;x64 - + diff --git a/src/GameFinder.RegistryUtils/GameFinder.RegistryUtils.csproj b/src/GameFinder.RegistryUtils/GameFinder.RegistryUtils.csproj index 3405a2c9..3321cca7 100644 --- a/src/GameFinder.RegistryUtils/GameFinder.RegistryUtils.csproj +++ b/src/GameFinder.RegistryUtils/GameFinder.RegistryUtils.csproj @@ -1,6 +1,7 @@ GameCollector.RegistryUtils + AnyCPU;x64 diff --git a/src/GameFinder.StoreHandlers.EADesktop/GameFinder.StoreHandlers.EADesktop.csproj b/src/GameFinder.StoreHandlers.EADesktop/GameFinder.StoreHandlers.EADesktop.csproj index ca8fb309..ed36abae 100644 --- a/src/GameFinder.StoreHandlers.EADesktop/GameFinder.StoreHandlers.EADesktop.csproj +++ b/src/GameFinder.StoreHandlers.EADesktop/GameFinder.StoreHandlers.EADesktop.csproj @@ -3,6 +3,7 @@ Library for finding games installed with EA Desktop. ea ea-desktop ea-app games GameCollector.StoreHandlers.EADesktop + AnyCPU;x64 diff --git a/src/GameFinder.StoreHandlers.EGS/GameFinder.StoreHandlers.EGS.csproj b/src/GameFinder.StoreHandlers.EGS/GameFinder.StoreHandlers.EGS.csproj index e9539fac..a4ffa84d 100644 --- a/src/GameFinder.StoreHandlers.EGS/GameFinder.StoreHandlers.EGS.csproj +++ b/src/GameFinder.StoreHandlers.EGS/GameFinder.StoreHandlers.EGS.csproj @@ -3,6 +3,7 @@ Library for finding games owned and installed with the Epic Games Store. epic egs epic-games-store games GameCollector.StoreHandlers.EGS + AnyCPU;x64 diff --git a/src/GameFinder.StoreHandlers.GOG/GameFinder.StoreHandlers.GOG.csproj b/src/GameFinder.StoreHandlers.GOG/GameFinder.StoreHandlers.GOG.csproj index 46c43491..eb324201 100644 --- a/src/GameFinder.StoreHandlers.GOG/GameFinder.StoreHandlers.GOG.csproj +++ b/src/GameFinder.StoreHandlers.GOG/GameFinder.StoreHandlers.GOG.csproj @@ -3,6 +3,7 @@ Library for finding games owned and installed with GOG Galaxy. gog gog-galaxy games GameCollector.StoreHandlers.GOG + AnyCPU;x64 diff --git a/src/GameFinder.StoreHandlers.Origin/GameFinder.StoreHandlers.Origin.csproj b/src/GameFinder.StoreHandlers.Origin/GameFinder.StoreHandlers.Origin.csproj index 07571807..410ff23a 100644 --- a/src/GameFinder.StoreHandlers.Origin/GameFinder.StoreHandlers.Origin.csproj +++ b/src/GameFinder.StoreHandlers.Origin/GameFinder.StoreHandlers.Origin.csproj @@ -3,6 +3,7 @@ Library for finding games installed with Origin. ea origin games GameCollector.StoreHandlers.Origin + AnyCPU;x64 diff --git a/src/GameFinder.StoreHandlers.Steam/GameFinder.StoreHandlers.Steam.csproj b/src/GameFinder.StoreHandlers.Steam/GameFinder.StoreHandlers.Steam.csproj index fe40ae1d..b7a93208 100644 --- a/src/GameFinder.StoreHandlers.Steam/GameFinder.StoreHandlers.Steam.csproj +++ b/src/GameFinder.StoreHandlers.Steam/GameFinder.StoreHandlers.Steam.csproj @@ -3,6 +3,7 @@ Library for finding games owned and installed with Steam. valve steam games GameCollector.StoreHandlers.Steam + AnyCPU;x64 @@ -17,7 +18,7 @@ - + diff --git a/src/GameFinder.StoreHandlers.Steam/ProtonWinePrefix.cs b/src/GameFinder.StoreHandlers.Steam/ProtonWinePrefix.cs index 3511410c..dd218762 100644 --- a/src/GameFinder.StoreHandlers.Steam/ProtonWinePrefix.cs +++ b/src/GameFinder.StoreHandlers.Steam/ProtonWinePrefix.cs @@ -1,3 +1,4 @@ +#if !WIN64 using System.Diagnostics.CodeAnalysis; using GameCollector.Wine; using JetBrains.Annotations; @@ -53,3 +54,4 @@ public AbsolutePath GetVersionFile() return ProtonDirectory.Combine("version"); } } +#endif diff --git a/src/GameFinder.StoreHandlers.Steam/SteamGame.cs b/src/GameFinder.StoreHandlers.Steam/SteamGame.cs index f1a3e2e5..1a94da62 100644 --- a/src/GameFinder.StoreHandlers.Steam/SteamGame.cs +++ b/src/GameFinder.StoreHandlers.Steam/SteamGame.cs @@ -77,6 +77,7 @@ public sealed record SteamGame(AbsolutePath SteamPath, /// public AbsolutePath GetCloudSavesDirectoryPath() => AppManifest is not null ? AppManifest.GetUserDataDirectoryPath(SteamPath) : new(); +#if !WIN64 /// /// Gets the Wine prefix managed by Proton for this game, if it exists. /// @@ -92,6 +93,7 @@ public sealed record SteamGame(AbsolutePath SteamPath, ProtonDirectory = protonDirectory, }; } +#endif /// /// Uses to parse the workshop manifest diff --git a/src/GameFinder.StoreHandlers.Xbox/GameFinder.StoreHandlers.Xbox.csproj b/src/GameFinder.StoreHandlers.Xbox/GameFinder.StoreHandlers.Xbox.csproj index a21f0dd7..4532a9f2 100644 --- a/src/GameFinder.StoreHandlers.Xbox/GameFinder.StoreHandlers.Xbox.csproj +++ b/src/GameFinder.StoreHandlers.Xbox/GameFinder.StoreHandlers.Xbox.csproj @@ -3,6 +3,7 @@ Library for finding games installed with Xbox Game Pass. xbox game pass games GameCollector.StoreHandlers.Xbox + AnyCPU;x64 diff --git a/src/GameFinder.Wine/GameFinder.Wine.csproj b/src/GameFinder.Wine/GameFinder.Wine.csproj index 82f8ab66..d4d2882b 100644 --- a/src/GameFinder.Wine/GameFinder.Wine.csproj +++ b/src/GameFinder.Wine/GameFinder.Wine.csproj @@ -3,6 +3,7 @@ Library for finding Wine prefixes. wine games linux GameCollector.Wine + AnyCPU;x64 diff --git a/src/GameFinder/GameFinder.csproj b/src/GameFinder/GameFinder.csproj index 2f9962dd..6f2e431a 100644 --- a/src/GameFinder/GameFinder.csproj +++ b/src/GameFinder/GameFinder.csproj @@ -1,6 +1,7 @@ GameCollector + AnyCPU;x64 @@ -50,4 +51,8 @@ + + + + diff --git a/tests/GameFinder.Common.Tests/GameFinder.Common.Tests.csproj b/tests/GameFinder.Common.Tests/GameFinder.Common.Tests.csproj index 22a419aa..abf1ce9c 100644 --- a/tests/GameFinder.Common.Tests/GameFinder.Common.Tests.csproj +++ b/tests/GameFinder.Common.Tests/GameFinder.Common.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.RegistryUtils.Tests/GameFinder.RegistryUtils.Tests.csproj b/tests/GameFinder.RegistryUtils.Tests/GameFinder.RegistryUtils.Tests.csproj index de6e13eb..f85ade28 100644 --- a/tests/GameFinder.RegistryUtils.Tests/GameFinder.RegistryUtils.Tests.csproj +++ b/tests/GameFinder.RegistryUtils.Tests/GameFinder.RegistryUtils.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.StoreHandlers.EADesktop.Tests/GameFinder.StoreHandlers.EADesktop.Tests.csproj b/tests/GameFinder.StoreHandlers.EADesktop.Tests/GameFinder.StoreHandlers.EADesktop.Tests.csproj index a16c83fe..1277c0c2 100644 --- a/tests/GameFinder.StoreHandlers.EADesktop.Tests/GameFinder.StoreHandlers.EADesktop.Tests.csproj +++ b/tests/GameFinder.StoreHandlers.EADesktop.Tests/GameFinder.StoreHandlers.EADesktop.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.StoreHandlers.EGS.Tests/GameFinder.StoreHandlers.EGS.Tests.csproj b/tests/GameFinder.StoreHandlers.EGS.Tests/GameFinder.StoreHandlers.EGS.Tests.csproj index 997f0409..f074af68 100644 --- a/tests/GameFinder.StoreHandlers.EGS.Tests/GameFinder.StoreHandlers.EGS.Tests.csproj +++ b/tests/GameFinder.StoreHandlers.EGS.Tests/GameFinder.StoreHandlers.EGS.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.StoreHandlers.GOG.Tests/GameFinder.StoreHandlers.GOG.Tests.csproj b/tests/GameFinder.StoreHandlers.GOG.Tests/GameFinder.StoreHandlers.GOG.Tests.csproj index dda66935..2d9b49cb 100644 --- a/tests/GameFinder.StoreHandlers.GOG.Tests/GameFinder.StoreHandlers.GOG.Tests.csproj +++ b/tests/GameFinder.StoreHandlers.GOG.Tests/GameFinder.StoreHandlers.GOG.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.StoreHandlers.Origin.Tests/GameFinder.StoreHandlers.Origin.Tests.csproj b/tests/GameFinder.StoreHandlers.Origin.Tests/GameFinder.StoreHandlers.Origin.Tests.csproj index 97abd25c..3e57a067 100644 --- a/tests/GameFinder.StoreHandlers.Origin.Tests/GameFinder.StoreHandlers.Origin.Tests.csproj +++ b/tests/GameFinder.StoreHandlers.Origin.Tests/GameFinder.StoreHandlers.Origin.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.StoreHandlers.Steam.Tests/GameFinder.StoreHandlers.Steam.Tests.csproj b/tests/GameFinder.StoreHandlers.Steam.Tests/GameFinder.StoreHandlers.Steam.Tests.csproj index eb2f955f..940417b9 100644 --- a/tests/GameFinder.StoreHandlers.Steam.Tests/GameFinder.StoreHandlers.Steam.Tests.csproj +++ b/tests/GameFinder.StoreHandlers.Steam.Tests/GameFinder.StoreHandlers.Steam.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.StoreHandlers.Xbox.Tests/GameFinder.StoreHandlers.Xbox.Tests.csproj b/tests/GameFinder.StoreHandlers.Xbox.Tests/GameFinder.StoreHandlers.Xbox.Tests.csproj index f7b92103..59e3ad48 100644 --- a/tests/GameFinder.StoreHandlers.Xbox.Tests/GameFinder.StoreHandlers.Xbox.Tests.csproj +++ b/tests/GameFinder.StoreHandlers.Xbox.Tests/GameFinder.StoreHandlers.Xbox.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/GameFinder.Wine.Tests/GameFinder.Wine.Tests.csproj b/tests/GameFinder.Wine.Tests/GameFinder.Wine.Tests.csproj index 47118bd9..02b46ddd 100644 --- a/tests/GameFinder.Wine.Tests/GameFinder.Wine.Tests.csproj +++ b/tests/GameFinder.Wine.Tests/GameFinder.Wine.Tests.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 + diff --git a/tests/TestUtils/TestUtils.csproj b/tests/TestUtils/TestUtils.csproj index 22a419aa..abf1ce9c 100644 --- a/tests/TestUtils/TestUtils.csproj +++ b/tests/TestUtils/TestUtils.csproj @@ -1,4 +1,7 @@ + + AnyCPU;x64 +