diff --git a/Directory.Packages.props b/Directory.Packages.props index fbca787c..a59812ef 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -38,10 +38,10 @@ Version="4.7.0" /> + Version="2.0.34.1" /> + Version="17.10.4" /> + Version="5.3.8" /> @@ -95,7 +95,7 @@ Condition="'$(EnableSourceLink)' != 'false'" /> @@ -45,17 +45,6 @@ -MTGOSDK.API.Events; -MTGOSDK.API.Interface.*; - diff --git a/MTGOSDK.Tests/packages.lock.json b/MTGOSDK.Tests/packages.lock.json index 3e57774a..d9432a1a 100644 --- a/MTGOSDK.Tests/packages.lock.json +++ b/MTGOSDK.Tests/packages.lock.json @@ -10,15 +10,9 @@ }, "DotNet.ReproducibleBuilds": { "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } + "requested": "[1.2.4, )", + "resolved": "1.2.4", + "contentHash": "Ch9U74tQA2fQH+U0hcYH7WyIFUfAq7jrjgSHVu2FAcYiMBtbrCMyq2nGA/ZZnB2jSaUeOOYiCjxeaDVB7Ssbdw==" }, "Microsoft.Extensions.Logging": { "type": "Direct", @@ -53,9 +47,9 @@ }, "Nerdbank.GitVersioning": { "type": "Direct", - "requested": "[3.6.133, )", - "resolved": "3.6.133", - "contentHash": "VZWMd5YAeDxpjWjAP/X6bAxnRMiEf6tES/ITN0X5CHJgkWLLeHGmEALivmTAfYM6P+P/3Szy6VCITUAkqjcHVw==" + "requested": "[3.6.139, )", + "resolved": "3.6.139", + "contentHash": "rq0Ub/Jik7PtMtZtLn0tHuJ01Yt36RQ+eeBe+S7qnJ/EFOX6D4T9zuYD3vQPYKGI6Ro4t2iWgFm3fGDgjBrMfg==" }, "NUnit": { "type": "Direct", @@ -77,9 +71,9 @@ }, "ReportGenerator": { "type": "Direct", - "requested": "[5.3.6, )", - "resolved": "5.3.6", - "contentHash": "cFmyBJGbD4eaE/qkwMclhcgqgrqktb0WmiZ8kt8i4ahIq5fr7SNVjVtAorbbh43vAXtvGPtD/ZUHZYqtAywM4A==" + "requested": "[5.3.8, )", + "resolved": "5.3.8", + "contentHash": "F+JLYA1c3uXMob8f8Wx6APRzZyvcsr5NVGsQOApBeOsyu1rZamWkfb68akm4aR5rfRXMytZsPGFou8xDJV+IcQ==" }, "Dynamitey": { "type": "Transitive", @@ -159,38 +153,11 @@ "resolved": "1.1.0", "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "Microsoft.SourceLink.Common": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", "resolved": "17.10.0", diff --git a/MTGOSDK.Tests/src/Tests/Events.cs b/MTGOSDK.Tests/src/Tests/Events.cs index 798266c1..cd8b0d12 100644 --- a/MTGOSDK.Tests/src/Tests/Events.cs +++ b/MTGOSDK.Tests/src/Tests/Events.cs @@ -155,7 +155,7 @@ public void ValidateLeague(League league) Assert.That(league.MinMatches, Is.GreaterThanOrEqualTo(3)); Assert.That((bool?)league.IsPaused, Is.Not.Null); - foreach(LeaderboardEntry entry in league.Leaderboard) + foreach(LeaderboardEntry entry in league.Leaderboard.Take(5)) { Assert.That(entry.Name, Is.Not.Empty); Assert.That(entry.TrophyCount, Is.GreaterThanOrEqualTo(0)); diff --git a/MTGOSDK.Win32/packages.lock.json b/MTGOSDK.Win32/packages.lock.json index dd71cd18..184e19af 100644 --- a/MTGOSDK.Win32/packages.lock.json +++ b/MTGOSDK.Win32/packages.lock.json @@ -4,15 +4,9 @@ ".NETStandard,Version=v2.0": { "DotNet.ReproducibleBuilds": { "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } + "requested": "[1.2.4, )", + "resolved": "1.2.4", + "contentHash": "Ch9U74tQA2fQH+U0hcYH7WyIFUfAq7jrjgSHVu2FAcYiMBtbrCMyq2nGA/ZZnB2jSaUeOOYiCjxeaDVB7Ssbdw==" }, "Iced": { "type": "Direct", @@ -22,9 +16,9 @@ }, "Meziantou.Polyfill": { "type": "Direct", - "requested": "[1.0.37, )", - "resolved": "1.0.37", - "contentHash": "kFlH4Ye5lEK9AjViSWm32JrH3Ee42jd15FNnv4X4fK4JzdSlkMR7mqzsgRCBgZzszWLr0ioIA78dsMNxRoouSw==" + "requested": "[1.0.39, )", + "resolved": "1.0.39", + "contentHash": "hqeFk63pjJvovNTl1fnTDcIB7XTt7uiD1O9bNHRi94JIZ31ILkKsb/Gv32U0RGMScddQUp4KZGYkgSpw1zozog==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", @@ -50,9 +44,9 @@ }, "Nerdbank.GitVersioning": { "type": "Direct", - "requested": "[3.6.133, )", - "resolved": "3.6.133", - "contentHash": "VZWMd5YAeDxpjWjAP/X6bAxnRMiEf6tES/ITN0X5CHJgkWLLeHGmEALivmTAfYM6P+P/3Szy6VCITUAkqjcHVw==" + "requested": "[3.6.139, )", + "resolved": "3.6.139", + "contentHash": "rq0Ub/Jik7PtMtZtLn0tHuJ01Yt36RQ+eeBe+S7qnJ/EFOX6D4T9zuYD3vQPYKGI6Ro4t2iWgFm3fGDgjBrMfg==" }, "NETStandard.Library": { "type": "Direct", @@ -73,38 +67,11 @@ "resolved": "1.1.0", "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "Microsoft.SourceLink.Common": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "System.Buffers": { "type": "Transitive", "resolved": "4.5.1", diff --git a/MTGOSDK/lib/ILLink/ILLink.props b/MTGOSDK/lib/ILLink/ILLink.props index d669a88a..fc7f19c4 100644 --- a/MTGOSDK/lib/ILLink/ILLink.props +++ b/MTGOSDK/lib/ILLink/ILLink.props @@ -48,6 +48,8 @@ $(NoWarn);IL2092;IL2093;IL2094;IL2095 $(NoWarn);IL2097;IL2098;IL2099 + + $(NoWarn);IL2121 + + true + + + - $(MSBuildThisFileDirectory)..\ILRepack\ILRepack.targets Microsoft.Diagnostics.Runtime $(SolutionDir)dist\$(Configuration)\$(ILRepackTarget).dll - true + + + diff --git a/MTGOSDK/lib/ScubaDiver/packages.lock.json b/MTGOSDK/lib/ScubaDiver/packages.lock.json index dc0ceb5a..a3a3ab95 100644 --- a/MTGOSDK/lib/ScubaDiver/packages.lock.json +++ b/MTGOSDK/lib/ScubaDiver/packages.lock.json @@ -4,27 +4,21 @@ ".NETStandard,Version=v2.0": { "DotNet.ReproducibleBuilds": { "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } + "requested": "[1.2.4, )", + "resolved": "1.2.4", + "contentHash": "Ch9U74tQA2fQH+U0hcYH7WyIFUfAq7jrjgSHVu2FAcYiMBtbrCMyq2nGA/ZZnB2jSaUeOOYiCjxeaDVB7Ssbdw==" }, "ILRepack.Lib.MSBuild.Task": { "type": "Direct", - "requested": "[2.0.33, )", - "resolved": "2.0.33", - "contentHash": "mbWjnc+7Z9qdJTNWubqCbU8pWgUxkgIJOny3lnejF7RVdZVWZyH9FhFoz+p9qJ9Z7tim5kE2um/NCGUdKBNSfA==" + "requested": "[2.0.34.1, )", + "resolved": "2.0.34.1", + "contentHash": "QHqCm+bTalw4/Jl+k0l0llUJmsv7ftkxZN+CnXdbJ4Fy6Xr2I+OGq4qY5rma+vRAy1veGQCCBcUr+VFVNwBi5A==" }, "Meziantou.Polyfill": { "type": "Direct", - "requested": "[1.0.37, )", - "resolved": "1.0.37", - "contentHash": "kFlH4Ye5lEK9AjViSWm32JrH3Ee42jd15FNnv4X4fK4JzdSlkMR7mqzsgRCBgZzszWLr0ioIA78dsMNxRoouSw==" + "requested": "[1.0.39, )", + "resolved": "1.0.39", + "contentHash": "hqeFk63pjJvovNTl1fnTDcIB7XTt7uiD1O9bNHRi94JIZ31ILkKsb/Gv32U0RGMScddQUp4KZGYkgSpw1zozog==" }, "Microsoft.Diagnostics.Runtime": { "type": "Direct", @@ -151,38 +145,11 @@ "resolved": "1.1.0", "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "Microsoft.SourceLink.Common": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "System.Buffers": { "type": "Transitive", "resolved": "4.5.1", diff --git a/MTGOSDK/lib/ScubaDiver/src/Diver.cs b/MTGOSDK/lib/ScubaDiver/src/Diver.cs index 41701611..824ef52b 100644 --- a/MTGOSDK/lib/ScubaDiver/src/Diver.cs +++ b/MTGOSDK/lib/ScubaDiver/src/Diver.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -21,17 +21,18 @@ using Microsoft.Diagnostics.Runtime; using Newtonsoft.Json; +using MTGOSDK.Core.Compiler; +using MTGOSDK.Core.Compiler.Extensions; +using MTGOSDK.Core.Compiler.Snapshot; using MTGOSDK.Core.Reflection; -using MTGOSDK.Core.Reflection.Snapshot; -using MTGOSDK.Core.Reflection.Emit; +using MTGOSDK.Core.Reflection.Extensions; +using MTGOSDK.Core.Reflection.Types; using MTGOSDK.Core.Remoting.Interop; -using MTGOSDK.Core.Remoting.Interop.Extensions; using MTGOSDK.Core.Remoting.Interop.Interactions; using MTGOSDK.Core.Remoting.Interop.Interactions.Callbacks; using MTGOSDK.Core.Remoting.Interop.Interactions.Client; using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; using MTGOSDK.Core.Remoting.Interop.Interactions.Object; -using MTGOSDK.Core.Remoting.Interop.Utils; using MTGOSDK.Win32.API; @@ -165,6 +166,7 @@ private void HandleDispatchedRequest(HttpListenerContext requestContext) } catch (Exception ex) { + Logger.Debug("[Diver] Exception in handler: " + ex.ToString()); body = QuickError(ex.Message, ex.StackTrace); } } @@ -218,8 +220,7 @@ void ListenerCallback(IAsyncResult result) } catch (Exception e) { - Logger.Debug("[Diver] Task faulted! Exception:"); - Logger.Debug(e.ToString()); + Logger.Debug("[Diver] Task faulted! Exception: " + e.ToString()); } } IAsyncResult asyncOperation = listener.BeginGetContext(ListenerCallback, listener); @@ -316,31 +317,21 @@ private string MakeUnregisterClientResponse(HttpListenerRequest arg) private string MakeDomainsResponse(HttpListenerRequest req) { - List available = new(); + // Extract the names of all available modules from the current AppDomain. + List modules = new(); + string currentDomain = AppDomain.CurrentDomain.FriendlyName; lock (_runtime.clrLock) { - foreach (ClrAppDomain clrAppDomain in _runtime.GetClrAppDomains()) - { - var modules = clrAppDomain.Modules - .Select(m => Path.GetFileNameWithoutExtension(m.Name)) - .Where(m => !string.IsNullOrWhiteSpace(m)) - .ToList(); - var dom = new DomainsDump.AvailableDomain() - { - Name = clrAppDomain.Name, - AvailableModules = modules - }; - available.Add(dom); - } + ClrAppDomain clrAppDomain = _runtime.GetClrAppDomains() + .FirstOrDefault(ad => ad.Name == currentDomain); + modules = clrAppDomain.Modules + .Select(m => Path.GetFileNameWithoutExtension(m.Name)) + .Where(m => !string.IsNullOrWhiteSpace(m)) + .ToList(); } - DomainsDump dd = new() - { - Current = AppDomain.CurrentDomain.FriendlyName, - AvailableDomains = available - }; - - return JsonConvert.SerializeObject(dd); + DomainDump domainDump = new(currentDomain, modules); + return JsonConvert.SerializeObject(domainDump); } private string MakeTypesResponse(HttpListenerRequest req) @@ -789,7 +780,7 @@ private string MakeInvokeResponse(HttpListenerRequest arg) dumpedObjType = _runtime.ResolveType(clrObj.Type.Name); try { - instance = _runtime.DereferenceObject(clrObj.Address, mt); + instance = _runtime.Compile(clrObj.Address, mt); } catch (Exception) { @@ -817,7 +808,7 @@ private string MakeInvokeResponse(HttpListenerRequest arg) // Infer parameter types from received parameters. // Note that for 'null' arguments we don't know the type so we use a "Wild Card" type - Type[] argumentTypes = paramsList.Select(p => p?.GetType() ?? new WildCardType()).ToArray(); + Type[] argumentTypes = paramsList.Select(p => p?.GetType() ?? new TypeStub()).ToArray(); // Get types of generic arguments Type[] genericArgumentTypes = request.GenericArgsTypeFullNames.Select(typeFullName => _runtime.ResolveType(typeFullName)).ToArray(); @@ -1035,7 +1026,7 @@ private string MakeSetFieldResponse(HttpListenerRequest arg) clrObj = _runtime.GetClrObject(request.ObjAddress); if (clrObj.Type == null) { - return QuickError("'address' points at an invalid address"); + return QuickError($"The invalid address for '${request.TypeFullName}'."); } // Make sure it's still in place @@ -1045,14 +1036,14 @@ private string MakeSetFieldResponse(HttpListenerRequest arg) if (clrObj.Type == null) { return - QuickError("Object moved since last refresh. 'address' now points at an invalid address."); + QuickError($"The address for '${request.TypeFullName}' moved since last refresh."); } ulong mt = clrObj.Type.MethodTable; dumpedObjType = _runtime.ResolveType(clrObj.Type.Name); try { - instance = _runtime.DereferenceObject(clrObj.Address, mt); + instance = _runtime.Compile(clrObj.Address, mt); } catch (Exception) { diff --git a/MTGOSDK/lib/ScubaDiver/src/DllEntry.cs b/MTGOSDK/lib/ScubaDiver/src/DllEntry.cs index f3288c08..35313def 100644 --- a/MTGOSDK/lib/ScubaDiver/src/DllEntry.cs +++ b/MTGOSDK/lib/ScubaDiver/src/DllEntry.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; diff --git a/MTGOSDK/lib/ScubaDiver/src/Logger.cs b/MTGOSDK/lib/ScubaDiver/src/Logger.cs index 993e59ff..e8cad1f0 100644 --- a/MTGOSDK/lib/ScubaDiver/src/Logger.cs +++ b/MTGOSDK/lib/ScubaDiver/src/Logger.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -37,7 +37,7 @@ internal class Logger #endregion -#if DEBUG +#if DEBUG && ENABLE_DEBUG_CONSOLE public static bool IsDebug = true; #else public static bool IsDebug = false; @@ -60,7 +60,8 @@ internal static void Debug(string s) { if (IsDebug || Debugger.IsAttached) { - System.Diagnostics.Debug.WriteLine(s); + Console.WriteLine(s); + // System.Diagnostics.Debug.WriteLine(s); } } } diff --git a/MTGOSDK/packages.lock.json b/MTGOSDK/packages.lock.json index b193b61f..105aa06f 100644 --- a/MTGOSDK/packages.lock.json +++ b/MTGOSDK/packages.lock.json @@ -4,15 +4,9 @@ ".NETStandard,Version=v2.0": { "DotNet.ReproducibleBuilds": { "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } + "requested": "[1.2.4, )", + "resolved": "1.2.4", + "contentHash": "Ch9U74tQA2fQH+U0hcYH7WyIFUfAq7jrjgSHVu2FAcYiMBtbrCMyq2nGA/ZZnB2jSaUeOOYiCjxeaDVB7Ssbdw==" }, "ImpromptuInterface": { "type": "Direct", @@ -27,9 +21,9 @@ }, "Meziantou.Polyfill": { "type": "Direct", - "requested": "[1.0.37, )", - "resolved": "1.0.37", - "contentHash": "kFlH4Ye5lEK9AjViSWm32JrH3Ee42jd15FNnv4X4fK4JzdSlkMR7mqzsgRCBgZzszWLr0ioIA78dsMNxRoouSw==" + "requested": "[1.0.39, )", + "resolved": "1.0.39", + "contentHash": "hqeFk63pjJvovNTl1fnTDcIB7XTt7uiD1O9bNHRi94JIZ31ILkKsb/Gv32U0RGMScddQUp4KZGYkgSpw1zozog==" }, "Microsoft.CSharp": { "type": "Direct", @@ -190,38 +184,11 @@ "resolved": "1.1.0", "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "Microsoft.SourceLink.Common": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "System.Buffers": { "type": "Transitive", "resolved": "4.5.1", @@ -345,21 +312,15 @@ "net8.0-windows7.0": { "DotNet.ReproducibleBuilds": { "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } + "requested": "[1.2.4, )", + "resolved": "1.2.4", + "contentHash": "Ch9U74tQA2fQH+U0hcYH7WyIFUfAq7jrjgSHVu2FAcYiMBtbrCMyq2nGA/ZZnB2jSaUeOOYiCjxeaDVB7Ssbdw==" }, "ILRepack.Lib.MSBuild.Task": { "type": "Direct", - "requested": "[2.0.33, )", - "resolved": "2.0.33", - "contentHash": "mbWjnc+7Z9qdJTNWubqCbU8pWgUxkgIJOny3lnejF7RVdZVWZyH9FhFoz+p9qJ9Z7tim5kE2um/NCGUdKBNSfA==" + "requested": "[2.0.34.1, )", + "resolved": "2.0.34.1", + "contentHash": "QHqCm+bTalw4/Jl+k0l0llUJmsv7ftkxZN+CnXdbJ4Fy6Xr2I+OGq4qY5rma+vRAy1veGQCCBcUr+VFVNwBi5A==" }, "ImpromptuInterface": { "type": "Direct", @@ -416,9 +377,9 @@ }, "Nerdbank.GitVersioning": { "type": "Direct", - "requested": "[3.6.133, )", - "resolved": "3.6.133", - "contentHash": "VZWMd5YAeDxpjWjAP/X6bAxnRMiEf6tES/ITN0X5CHJgkWLLeHGmEALivmTAfYM6P+P/3Szy6VCITUAkqjcHVw==" + "requested": "[3.6.139, )", + "resolved": "3.6.139", + "contentHash": "rq0Ub/Jik7PtMtZtLn0tHuJ01Yt36RQ+eeBe+S7qnJ/EFOX6D4T9zuYD3vQPYKGI6Ro4t2iWgFm3fGDgjBrMfg==" }, "Newtonsoft.Json": { "type": "Direct", @@ -499,38 +460,11 @@ "resolved": "1.1.0", "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "Microsoft.SourceLink.Common": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, "System.ComponentModel": { "type": "Transitive", "resolved": "4.3.0", diff --git a/MTGOSDK/src/API/Chat/Channel.cs b/MTGOSDK/src/API/Chat/Channel.cs index 0093aed5..5dd9edc0 100644 --- a/MTGOSDK/src/API/Chat/Channel.cs +++ b/MTGOSDK/src/API/Chat/Channel.cs @@ -73,7 +73,7 @@ public sealed class Channel(dynamic chatChannel) /// /// The log of messages in this channel. /// - public IList Messages => Map(ChatLog); + public IList Messages => Map(ChatLog, proxy: true); /// /// The number of messages sent in this channel. diff --git a/MTGOSDK/src/API/Client.cs b/MTGOSDK/src/API/Client.cs index e8b336de..d55dd1f6 100644 --- a/MTGOSDK/src/API/Client.cs +++ b/MTGOSDK/src/API/Client.cs @@ -134,7 +134,7 @@ public sealed class Client : DLRWrapper, IDisposable /// and should be instantiated once per application instance and prior to /// invoking with other API classes. /// - /// + /// /// Thrown when the client process fails to finish installation or start. /// /// @@ -167,7 +167,7 @@ public Client( throw new ExternalErrorException("MTGO servers are currently offline."); if (!await RemoteClient.StartProcess()) - throw new SetupFailedException("Failed to start the MTGO process."); + throw new SetupFailureException("Failed to start the MTGO process."); } // Sets the client's disposal policy. diff --git a/MTGOSDK/src/API/Collection/Binder.cs b/MTGOSDK/src/API/Collection/Binder.cs index 1ed54544..6fb6f67b 100644 --- a/MTGOSDK/src/API/Collection/Binder.cs +++ b/MTGOSDK/src/API/Collection/Binder.cs @@ -16,6 +16,7 @@ public sealed class Binder(dynamic binder) : CardGrouping /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(IBinder); /// diff --git a/MTGOSDK/src/API/Collection/Card.cs b/MTGOSDK/src/API/Collection/Card.cs index 08f302f0..3ea5c5bd 100644 --- a/MTGOSDK/src/API/Collection/Card.cs +++ b/MTGOSDK/src/API/Collection/Card.cs @@ -15,6 +15,7 @@ public sealed class Card(dynamic card) : CollectionItem /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(ICardDefinition); /// diff --git a/MTGOSDK/src/API/Collection/Collection.cs b/MTGOSDK/src/API/Collection/Collection.cs index 3455316a..a893b7fb 100644 --- a/MTGOSDK/src/API/Collection/Collection.cs +++ b/MTGOSDK/src/API/Collection/Collection.cs @@ -17,6 +17,7 @@ public sealed class Collection(ICollectionGrouping collection) /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(ICollectionGrouping); /// diff --git a/MTGOSDK/src/API/Collection/Deck.cs b/MTGOSDK/src/API/Collection/Deck.cs index f0d1b1bf..70d136a5 100644 --- a/MTGOSDK/src/API/Collection/Deck.cs +++ b/MTGOSDK/src/API/Collection/Deck.cs @@ -19,6 +19,7 @@ public sealed class Deck(dynamic deck) : CardGrouping /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(IDeck); /// @@ -51,7 +52,7 @@ public sealed class Deck(dynamic deck) : CardGrouping /// /// Proxy type for the client's DeckRegion class. /// - private static readonly Proxy s_DeckRegion = + private static readonly TypeProxy s_DeckRegion = new(typeof(WotC.MTGO.Common.DeckRegion)); public dynamic GetRegionRef(DeckRegion region) diff --git a/MTGOSDK/src/API/Interface/ViewModels/BasicToastViewModel.cs b/MTGOSDK/src/API/Interface/ViewModels/BasicToastViewModel.cs index eba754bd..862779a4 100644 --- a/MTGOSDK/src/API/Interface/ViewModels/BasicToastViewModel.cs +++ b/MTGOSDK/src/API/Interface/ViewModels/BasicToastViewModel.cs @@ -23,7 +23,7 @@ public sealed class BasicToastViewModel(dynamic basicToastViewModel) /// /// Creates a new remote instance of the BasicToastViewModel class. /// - internal static BasicToastViewModel NewInstance(params dynamic[] args) => + private static BasicToastViewModel NewInstance(params dynamic[] args) => new(RemoteClient.CreateInstance( "Shiny.Toast.ViewModels.BasicToastViewModel", Unbind(args) diff --git a/MTGOSDK/src/API/Interface/ViewModels/GenericDialogViewModel.cs b/MTGOSDK/src/API/Interface/ViewModels/GenericDialogViewModel.cs index 77a83a4b..b76f1f46 100644 --- a/MTGOSDK/src/API/Interface/ViewModels/GenericDialogViewModel.cs +++ b/MTGOSDK/src/API/Interface/ViewModels/GenericDialogViewModel.cs @@ -22,7 +22,7 @@ public sealed class GenericDialogViewModel(dynamic genericDialogViewModel) /// /// Creates a new remote instance of the GenericDialogViewModel class. /// - internal static GenericDialogViewModel NewInstance() => + private static GenericDialogViewModel NewInstance() => new(RemoteClient.CreateInstance("Shiny.ViewModels.GenericDialogViewModel")); public GenericDialogViewModel( diff --git a/MTGOSDK/src/API/Interface/WindowUtilities.cs b/MTGOSDK/src/API/Interface/WindowUtilities.cs index 9a2429a5..ec6ddd0c 100644 --- a/MTGOSDK/src/API/Interface/WindowUtilities.cs +++ b/MTGOSDK/src/API/Interface/WindowUtilities.cs @@ -52,7 +52,7 @@ public static ICollection GetWindows() try { var collection = RemoteClient - .GetInstances(new Proxy()) + .GetInstances(new TypeProxy()) .LastOrDefault() ?? throw null; return Bind>(collection); diff --git a/MTGOSDK/src/API/ObjectProvider.cs b/MTGOSDK/src/API/ObjectProvider.cs index 17f3d397..f1d1a758 100644 --- a/MTGOSDK/src/API/ObjectProvider.cs +++ b/MTGOSDK/src/API/ObjectProvider.cs @@ -9,7 +9,8 @@ using MTGOSDK.Core.Reflection; using MTGOSDK.Core.Remoting; using static MTGOSDK.Core.Reflection.DLRWrapper; -using static MTGOSDK.Core.Remoting.LazyRemoteObject; +using MTGOSDK.Core.Remoting.Reflection; +using TResetter = MTGOSDK.Core.Remoting.Reflection.LazyRemoteObject.TResetter; namespace MTGOSDK.API; @@ -22,7 +23,7 @@ public static class ObjectProvider /// /// Proxy type for the client's static ObjectProvider class. /// - private static readonly Proxy s_proxy = + private static readonly TypeProxy s_proxy = new(typeof(WotC.MtGO.Client.Common.ServiceLocation.ObjectProvider)); private static readonly ConcurrentDictionary s_instances = new(); @@ -177,7 +178,7 @@ public static dynamic Get( public static dynamic Get(bool bindTypes = true) where T : class { // Create a proxy type for the given generic type - Proxy proxy = new(); + TypeProxy proxy = new(); // // If not binding types, return an instance leaving open all binding flags. @@ -198,7 +199,7 @@ public static dynamic Get(bool bindTypes = true) where T : class // Late bind the interface type to the proxy value if (bindTypes && (@interface != null || proxy.IsInterface)) - obj = Proxy.As(obj, @interface ?? proxy.Class); + obj = TypeProxy.As(obj, @interface ?? proxy.Class); return obj; } diff --git a/MTGOSDK/src/API/Play/Games/Game.cs b/MTGOSDK/src/API/Play/Games/Game.cs index 7c04d82a..3b50a268 100644 --- a/MTGOSDK/src/API/Play/Games/Game.cs +++ b/MTGOSDK/src/API/Play/Games/Game.cs @@ -39,7 +39,7 @@ public sealed class Game(dynamic game) : DLRWrapper Optional( // TODO: Use a more efficient method of retrieving view model objects // without traversing the client's managed heap. - RemoteClient.GetInstances(new Proxy()) + RemoteClient.GetInstances(new TypeProxy()) .FirstOrDefault(vm => Try(() => vm.GameId == this.Id)) ); diff --git a/MTGOSDK/src/API/Play/History/HistoricalItem.cs b/MTGOSDK/src/API/Play/History/HistoricalItem.cs index d27ed800..c3c9e0eb 100644 --- a/MTGOSDK/src/API/Play/History/HistoricalItem.cs +++ b/MTGOSDK/src/API/Play/History/HistoricalItem.cs @@ -19,6 +19,7 @@ public abstract class HistoricalItem : DLRWrapper /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(I); public sealed class Default(dynamic historicalItem) diff --git a/MTGOSDK/src/API/Play/Leagues/League.cs b/MTGOSDK/src/API/Play/Leagues/League.cs index 6e83beb5..5727cdc3 100644 --- a/MTGOSDK/src/API/Play/Leagues/League.cs +++ b/MTGOSDK/src/API/Play/Leagues/League.cs @@ -19,6 +19,7 @@ public sealed class League(dynamic league) : Event /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(ILeague); /// @@ -69,7 +70,7 @@ public sealed class League(dynamic league) : Event /// The league's current leaderboard entries. /// public IList Leaderboard => - Map(@base.Leaderboard); + Map(@base.Leaderboard, proxy: true); /// /// The total number of matches playable in the league. diff --git a/MTGOSDK/src/API/Play/Match.cs b/MTGOSDK/src/API/Play/Match.cs index c5179488..32534893 100644 --- a/MTGOSDK/src/API/Play/Match.cs +++ b/MTGOSDK/src/API/Play/Match.cs @@ -21,6 +21,7 @@ public sealed class Match(dynamic match) : Event /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(IMatch); /// diff --git a/MTGOSDK/src/API/Play/Queue.cs b/MTGOSDK/src/API/Play/Queue.cs index bc0c4403..a2b7efbc 100644 --- a/MTGOSDK/src/API/Play/Queue.cs +++ b/MTGOSDK/src/API/Play/Queue.cs @@ -16,6 +16,7 @@ public sealed class Queue(dynamic queue) : Event /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(IQueue); /// diff --git a/MTGOSDK/src/API/Play/Tournaments/Tournament.cs b/MTGOSDK/src/API/Play/Tournaments/Tournament.cs index 7835e7eb..92a5b40c 100644 --- a/MTGOSDK/src/API/Play/Tournaments/Tournament.cs +++ b/MTGOSDK/src/API/Play/Tournaments/Tournament.cs @@ -18,6 +18,7 @@ public sealed class Tournament(dynamic tournament) : Event /// /// The internal reference for the binding type for the wrapped object. /// + [RuntimeInternal] internal override Type type => typeof(ITournament); /// @@ -59,7 +60,9 @@ public sealed class Tournament(dynamic tournament) : Event /// The time remaining in the current round or tournament phase. /// public TimeSpan TimeRemaining => - Cast(Unbind(@base).TimeRemaining); + State == TournamentState.BetweenRounds + ? TimeSpan.Zero + : Cast(Unbind(@base).TimeRemaining); /// /// The current round of the tournament. diff --git a/MTGOSDK/src/Core/Reflection/Emit/Converter.cs b/MTGOSDK/src/Core/Compiler/Converter.cs similarity index 96% rename from MTGOSDK/src/Core/Reflection/Emit/Converter.cs rename to MTGOSDK/src/Core/Compiler/Converter.cs index 20d44335..ea3ba016 100644 --- a/MTGOSDK/src/Core/Reflection/Emit/Converter.cs +++ b/MTGOSDK/src/Core/Compiler/Converter.cs @@ -1,16 +1,16 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; using System.Reflection.Emit; -using MTGOSDK.Core.Remoting.Interop.Extensions; +using MTGOSDK.Core.Compiler.Extensions; -namespace MTGOSDK.Core.Reflection.Emit; +namespace MTGOSDK.Core.Compiler; /// /// A class that converts an IntPtr to an object reference. diff --git a/MTGOSDK/src/Core/Compiler/Extensions/CallerExtensions.cs b/MTGOSDK/src/Core/Compiler/Extensions/CallerExtensions.cs new file mode 100644 index 00000000..daf03419 --- /dev/null +++ b/MTGOSDK/src/Core/Compiler/Extensions/CallerExtensions.cs @@ -0,0 +1,81 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; + +using MTGOSDK.Core.Reflection.Attributes; +using MTGOSDK.Core.Reflection.Extensions; + + +namespace MTGOSDK.Core.Compiler.Extensions; + +/// +/// Provides methods for parsing stack frames and tracing callers. +/// +public static class CallerExtensions +{ + /// + /// Gets the name of the caller. + /// + /// The stack frame depth. + /// The name of the caller. + public static string GetCallerName(int depth) => + new StackFrame(depth).GetMethod().Name + .Replace("get_", "") + .Replace("set_", ""); + + /// + /// Gets the parent type of the caller. + /// + /// The stack frame depth. + /// The type of the caller. + public static Type GetCallerType(int depth) => + new StackFrame(depth).GetMethod().ReflectedType; + + /// + /// Gets the stack frame depth of the caller. + /// + /// The starting stack frame depth. + /// The caller's stack frame depth. + public static int GetCallerDepth(int depth = 3) + { + Type wrapperType = GetCallerType(depth); + while(GetCallerType(depth).Name == wrapperType.Name && depth < 50) depth++; + + return depth; + } + + /// + /// Gets all members of the caller that have a specific attribute. + /// + private static MemberAttributePair[] GetCallerAttributes(int depth = 2) + where T : Attribute => + GetCallerType(depth).GetMemberAttributes(); + + /// + /// Gets a specific attribute of the caller, if it exists. + /// + /// The type of attribute. + /// The stack frame depth. + /// The attribute, or null if it does not exist. + public static T? GetCallerAttribute(int depth = 2) where T : Attribute + { + string name = GetCallerName(depth); + try + { + foreach (var memberAttributePair in GetCallerAttributes(depth+1)) + { + if (memberAttributePair.Member.Name == name) + return memberAttributePair.Attribute; + } + } + // Invalid member access (or otherwise doesn't have any attributes) + catch (NullReferenceException) { } + + return null; + } +} diff --git a/MTGOSDK/src/Core/Reflection/Snapshot/ClrExtensions.cs b/MTGOSDK/src/Core/Compiler/Extensions/ClrExtensions.cs similarity index 59% rename from MTGOSDK/src/Core/Reflection/Snapshot/ClrExtensions.cs rename to MTGOSDK/src/Core/Compiler/Extensions/ClrExtensions.cs index 096fd22f..56228742 100644 --- a/MTGOSDK/src/Core/Reflection/Snapshot/ClrExtensions.cs +++ b/MTGOSDK/src/Core/Compiler/Extensions/ClrExtensions.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -9,17 +9,21 @@ using System.Collections.Generic; using Microsoft.Diagnostics.Runtime; +using MTGOSDK.Core.Compiler.Structs; -namespace MTGOSDK.Core.Reflection.Snapshot; -public static class ClrExt -{ - public struct TypeDefToMethod - { - public ulong MethodTable { get; set; } - public int Token { get; set; } - } +namespace MTGOSDK.Core.Compiler.Extensions; +public static class ClrExtensions +{ + /// + /// Converts a ClrArray to a raw byte array. + /// + /// The ClrArray to convert. + /// The byte array. + /// + /// Thrown if the ClrArray is not a byte array. + /// public static byte[] ToByteArray(this ClrArray arr) { try @@ -40,11 +44,24 @@ public static byte[] ToByteArray(this ClrArray arr) return res; } + /// + /// Converts a ClrObject to a raw byte array. + /// + /// The ClrObject to convert. + /// The byte array. + /// + /// Thrown if the ClrObject is not an array. + /// public static byte[] ToByteArray(this ClrObject obj) { return obj.AsArray().ToByteArray(); } + /// + /// Enumerates the TypeDefToMethodTableMap for a ClrModule object. + /// + /// The ClrModule object. + /// An IEnumerable of TypeDefToMethod objects. public static IEnumerable EnumerateTypeDefToMethodTableMap(this ClrModule mod) { // EnumerateTypeDefToMethodTableMap wants to return an IEnumerable<(ulong,int)> diff --git a/MTGOSDK/src/Core/Remoting/Interop/Extensions/IntPtrExt.cs b/MTGOSDK/src/Core/Compiler/Extensions/IntPtrExtensions.cs similarity index 59% rename from MTGOSDK/src/Core/Remoting/Interop/Extensions/IntPtrExt.cs rename to MTGOSDK/src/Core/Compiler/Extensions/IntPtrExtensions.cs index bc945c37..ea40b806 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Extensions/IntPtrExt.cs +++ b/MTGOSDK/src/Core/Compiler/Extensions/IntPtrExtensions.cs @@ -1,15 +1,15 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Runtime.InteropServices; -namespace MTGOSDK.Core.Remoting.Interop.Extensions; +namespace MTGOSDK.Core.Compiler.Extensions; -public static class IntPtrExt +public static class IntPtrExtensions { public static IntPtr GetMethodTable(this IntPtr o) { @@ -20,7 +20,8 @@ public static IntPtr GetMethodTable(this IntPtr o) } catch (Exception e) { - throw new AccessViolationException("Failed to read MethodTable at the object's address.", e); + throw new AccessViolationException( + "Failed to read MethodTable at the object's address.", e); } } } diff --git a/MTGOSDK/src/Core/Compiler/Extensions/TypeExtensions.cs b/MTGOSDK/src/Core/Compiler/Extensions/TypeExtensions.cs new file mode 100644 index 00000000..ba49b3c9 --- /dev/null +++ b/MTGOSDK/src/Core/Compiler/Extensions/TypeExtensions.cs @@ -0,0 +1,41 @@ +/** @file + Copyright (c) 2023, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; + + +namespace MTGOSDK.Core.Compiler.Extensions; + +public static class TypeExtensions +{ + /// + /// Determines whether the type is compiler-generated. + /// + public static bool IsCompilerGenerated(this Type t) + { + if (t == null) return false; + + return t.IsDefined(typeof(CompilerGeneratedAttribute), false) + || IsCompilerGenerated(t.DeclaringType); + } + + /// + /// Extracts the base type from a compiler-generated type. + /// + /// The type to extract the base type from. + /// The base type of the given type. + public static Type GetBaseType(this Type t) + { + if (!t.IsCompilerGenerated()) return t; + + string fullName = t.FullName; + string baseName = fullName.Substring(0, fullName.IndexOf("+<")); + Type baseType = t.DeclaringType.Assembly.GetType(baseName); + + return baseType; + } +} diff --git a/MTGOSDK/src/Core/Reflection/Emit/FreezeFuncsFactory.cs b/MTGOSDK/src/Core/Compiler/FreezeFuncsFactory.cs similarity index 80% rename from MTGOSDK/src/Core/Reflection/Emit/FreezeFuncsFactory.cs rename to MTGOSDK/src/Core/Compiler/FreezeFuncsFactory.cs index 1aae8439..735f125a 100644 --- a/MTGOSDK/src/Core/Reflection/Emit/FreezeFuncsFactory.cs +++ b/MTGOSDK/src/Core/Compiler/FreezeFuncsFactory.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -10,19 +10,38 @@ using System.Runtime.CompilerServices; using System.Threading; +using MTGOSDK.Core.Compiler.Structs; -namespace MTGOSDK.Core.Reflection.Emit; +namespace MTGOSDK.Core.Compiler; + +/// +/// A factory for generating dynamic freeze functions to pin objects in memory. +/// public static class FreezeFuncsFactory { + /// + /// Represents a dynamic freeze function for pinning objects in memory. + /// public delegate void FreezeFunc( object[] objects, ulong[] addresses, ManualResetEvent frozenFeedback, ManualResetEvent unfreezeRequested); + /// + /// A local cache of generated freeze functions for each parameter count. + /// private static Dictionary _dict = new(); + /// + /// Generates a dynamic freeze function with the specified number of arguments. + /// + /// The number of arguments to freeze. + /// A delegate to the generated freeze function. + /// + /// This method caches the generated freeze functions for each parameter count. + /// public static FreezeFunc Generate(int numArguments) { if (!_dict.TryGetValue(numArguments, out FreezeFunc func)) @@ -33,11 +52,16 @@ public static FreezeFunc Generate(int numArguments) return func; } + /// + /// Generates a dynamic freeze function with the specified number of arguments. + /// + /// The number of arguments to freeze. + /// A delegate to the generated freeze function. private static FreezeFunc GenerateInternal(int numArguments) { // Create a dynamic method with the desired number of parameters var freezeMethod = new DynamicMethod( - "FreezeInternal_"+numArguments, + "FreezeInternal_" + numArguments, typeof(void), new[] { @@ -92,7 +116,7 @@ private static FreezeFunc GenerateInternal(int numArguments) typeof(Unsafe).GetMethod("As", new Type[1] { typeof(object) }) .MakeGenericMethod(typeof(Pinnable))); - // Load addess of fake "Data" field + // Load address of fake "Data" field // `c = &b.Data` il.Emit(OpCodes.Ldflda, typeof(Pinnable).GetField("Data")); diff --git a/MTGOSDK/src/Core/Reflection/Emit/FrozenObjectCollection.cs b/MTGOSDK/src/Core/Compiler/FrozenObjectCollection.cs similarity index 73% rename from MTGOSDK/src/Core/Reflection/Emit/FrozenObjectCollection.cs rename to MTGOSDK/src/Core/Compiler/FrozenObjectCollection.cs index e29c89e7..a4db5103 100644 --- a/MTGOSDK/src/Core/Reflection/Emit/FrozenObjectCollection.cs +++ b/MTGOSDK/src/Core/Compiler/FrozenObjectCollection.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Collections.Generic; @@ -10,8 +10,17 @@ using System.Threading.Tasks; -namespace MTGOSDK.Core.Reflection.Emit; +namespace MTGOSDK.Core.Compiler; +/// +/// A class that manages a collection of frozen (pinned) objects. +/// +/// +/// This class pins objects in memory and keeps track of their addresses as +/// they are pinned. This is useful for preventing the garbage collector from +/// moving objects in memory or for preserving pointers or references to objects +/// that are passed to unmanaged code. +/// public class FrozenObjectsCollection { private object _lock = new object(); @@ -31,6 +40,9 @@ public bool TryGetPinningAddress(object o, out ulong addr) } } + /// + /// Pins a collection of objects. + /// private void PinInternal(object[] newfrozenObjects) { lock (_lock) @@ -70,23 +82,33 @@ private void PinInternal(object[] newfrozenObjects) } } + /// + /// Pins an object and returns the address where it is pinned. + /// + /// The address where the object is pinned. + /// + /// If an object is already pinned, this method will simply return the address + /// where the object is pinned. + /// public ulong Pin(object o) { lock (_lock) { - if (_frozenObjects.TryGetValue(o, out ulong addr)) - return addr; + // If the object is already pinned, return it's address. + if (_frozenObjects.TryGetValue(o, out ulong addr)) return addr; // Prepare parameters object[] objs = _frozenObjects.Keys.Concat(new object[] { o }).ToArray(); PinInternal(objs); - // Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Pinned another object. Num Pinned: {_frozenObjects.Count}"); - return _frozenObjects[o]; } } + /// + /// Tries to get the object that is pinned at the given address. + /// + /// True if the object was found, false if not. public bool TryGetPinnedObject(ulong addr, out object? o) { lock (_lock) @@ -106,7 +128,7 @@ public bool TryGetPinnedObject(ulong addr, out object? o) } /// - /// Unpins an object + /// Unpins an object from the collection. /// /// True if it was pinned, false if not. public bool Unpin(ulong objAddress) @@ -132,6 +154,9 @@ public bool Unpin(ulong objAddress) } } + /// + /// Unpins all objects that are currently pinned. + /// public void UnpinAll() { lock (_lock) diff --git a/MTGOSDK/src/Core/Reflection/InstanceFactory.cs b/MTGOSDK/src/Core/Compiler/InstanceFactory.cs similarity index 86% rename from MTGOSDK/src/Core/Reflection/InstanceFactory.cs rename to MTGOSDK/src/Core/Compiler/InstanceFactory.cs index 988bbb50..cda58bfe 100644 --- a/MTGOSDK/src/Core/Reflection/InstanceFactory.cs +++ b/MTGOSDK/src/Core/Compiler/InstanceFactory.cs @@ -6,8 +6,10 @@ using System.Collections.Concurrent; using System.Linq.Expressions; +using MTGOSDK.Core.Reflection.Types; -namespace MTGOSDK.Core.Reflection; + +namespace MTGOSDK.Core.Compiler; /// /// A factory for creating instances of types with up to three constructor arguments. @@ -29,17 +31,17 @@ object arg3 public static object CreateInstance(Type type) { - return InstanceFactoryGeneric.CreateInstance(type, null, null, null); + return InstanceFactoryGeneric.CreateInstance(type, null, null, null); } public static object CreateInstance(Type type, TArg1 arg1) { - return InstanceFactoryGeneric.CreateInstance(type, arg1, null, null); + return InstanceFactoryGeneric.CreateInstance(type, arg1, null, null); } public static object CreateInstance(Type type, TArg1 arg1, TArg2 arg2) { - return InstanceFactoryGeneric.CreateInstance(type, arg1, arg2, null); + return InstanceFactoryGeneric.CreateInstance(type, arg1, arg2, null); } public static object CreateInstance(Type type, TArg1 arg1, TArg2 arg2, TArg3 arg3) @@ -66,9 +68,9 @@ public static object CreateInstance(Type type, params object[] args) var key = Tuple.Create( type, - arg0?.GetType() ?? typeof(TypeToIgnore), - arg1?.GetType() ?? typeof(TypeToIgnore), - arg2?.GetType() ?? typeof(TypeToIgnore)); + arg0?.GetType() ?? typeof(TypeStub), + arg1?.GetType() ?? typeof(TypeStub), + arg2?.GetType() ?? typeof(TypeStub)); if (cachedFuncs.TryGetValue(key, out CreateDelegate func)) return func(type, arg0, arg1, arg2); @@ -123,11 +125,11 @@ private static Func CacheFunc( TArg3 arg3) { var constructorTypes = new List(); - if (typeof(TArg1) != typeof(TypeToIgnore)) + if (typeof(TArg1) != typeof(TypeStub)) constructorTypes.Add(typeof(TArg1)); - if (typeof(TArg2) != typeof(TypeToIgnore)) + if (typeof(TArg2) != typeof(TypeStub)) constructorTypes.Add(typeof(TArg2)); - if (typeof(TArg3) != typeof(TypeToIgnore)) + if (typeof(TArg3) != typeof(TypeStub)) constructorTypes.Add(typeof(TArg3)); var parameters = new List() @@ -147,5 +149,3 @@ private static Func CacheFunc( return func; } } - -public class TypeToIgnore { } diff --git a/MTGOSDK/src/Core/Reflection/Snapshot/SnapshotRuntime.cs b/MTGOSDK/src/Core/Compiler/Snapshot/SnapshotRuntime.cs similarity index 97% rename from MTGOSDK/src/Core/Reflection/Snapshot/SnapshotRuntime.cs rename to MTGOSDK/src/Core/Compiler/Snapshot/SnapshotRuntime.cs index 48bf5131..eb3a7fe1 100644 --- a/MTGOSDK/src/Core/Reflection/Snapshot/SnapshotRuntime.cs +++ b/MTGOSDK/src/Core/Compiler/Snapshot/SnapshotRuntime.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -13,15 +13,15 @@ using System.Reflection; using Microsoft.Diagnostics.Runtime; -using MTGOSDK.Core.Reflection.Emit; +using MTGOSDK.Core.Compiler; +using MTGOSDK.Core.Compiler.Extensions; using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; -using MTGOSDK.Core.Remoting.Interop.Utils; using MTGOSDK.Win32.API; -namespace MTGOSDK.Core.Reflection.Snapshot; +namespace MTGOSDK.Core.Compiler.Snapshot; /// /// The snapshot runtime used to interact with the ClrMD runtime and snapshot @@ -31,6 +31,8 @@ public class SnapshotRuntime : IDisposable { internal static readonly object _clrMdLock = new(); // static public virtual object clrLock => SnapshotRuntime._clrMdLock; // non-static + + // Internal ClrMD runtime and data target objects to manage the snapshot. private DataTarget _dt; private ClrRuntime _runtime; @@ -142,10 +144,10 @@ public bool UnpinObject(ulong objAddress) // IL.Emit runtime converter methods // - public object DereferenceObject(IntPtr pObj, IntPtr expectedMethodTable) => + public object Compile(IntPtr pObj, IntPtr expectedMethodTable) => _converter.ConvertFromIntPtr(pObj, expectedMethodTable); - public object DereferenceObject(ulong pObj, ulong expectedMethodTable) => + public object Compile(ulong pObj, ulong expectedMethodTable) => _converter.ConvertFromIntPtr(pObj, expectedMethodTable); // @@ -414,7 +416,7 @@ public ImmutableArray GetClrAppDomains() object instance; try { - instance = DereferenceObject(finalObjAddress, methodTable); + instance = Compile(finalObjAddress, methodTable); } catch (ArgumentException) { @@ -505,7 +507,7 @@ public ImmutableArray GetClrAppDomains() object instance = null; try { - instance = DereferenceObject(clrObj.Address, mt); + instance = Compile(clrObj.Address, mt); } catch (Exception) { diff --git a/MTGOSDK/src/Core/Reflection/Snapshot/UnifiedAppDomain.cs b/MTGOSDK/src/Core/Compiler/Snapshot/UnifiedAppDomain.cs similarity index 94% rename from MTGOSDK/src/Core/Reflection/Snapshot/UnifiedAppDomain.cs rename to MTGOSDK/src/Core/Compiler/Snapshot/UnifiedAppDomain.cs index 3dad044c..cdc72d38 100644 --- a/MTGOSDK/src/Core/Reflection/Snapshot/UnifiedAppDomain.cs +++ b/MTGOSDK/src/Core/Compiler/Snapshot/UnifiedAppDomain.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -12,7 +12,7 @@ using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; -namespace MTGOSDK.Core.Reflection.Snapshot; +namespace MTGOSDK.Core.Compiler.Snapshot; /// /// Encapsulates access to all AppDomains in the process @@ -84,9 +84,9 @@ public Type ResolveType(string typeFullName, string assemblyName = null) typeFullName = $"{nonGenericPart}`{numOfParams}"; } - foreach (Assembly assm in _domains.SelectMany(d => d.GetAssemblies())) + foreach (Assembly asm in _domains.SelectMany(d => d.GetAssemblies())) { - Type t = assm.GetType(typeFullName, throwOnError: false); + Type t = asm.GetType(typeFullName, throwOnError: false); if (t != null) return t; } diff --git a/MTGOSDK/src/Core/Reflection/Emit/Pinnable.cs b/MTGOSDK/src/Core/Compiler/Structs/Pinnable.cs similarity index 79% rename from MTGOSDK/src/Core/Reflection/Emit/Pinnable.cs rename to MTGOSDK/src/Core/Compiler/Structs/Pinnable.cs index 5516c1cf..fe5766b1 100644 --- a/MTGOSDK/src/Core/Reflection/Emit/Pinnable.cs +++ b/MTGOSDK/src/Core/Compiler/Structs/Pinnable.cs @@ -1,13 +1,13 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Runtime.InteropServices; -namespace MTGOSDK.Core.Reflection.Emit; +namespace MTGOSDK.Core.Compiler.Structs; /// /// This class is used to make arbitrary objects "Pinnable" in the .NET @@ -15,7 +15,7 @@ namespace MTGOSDK.Core.Reflection.Emit; /// first field's address overlaps with this class's field. /// [StructLayout(LayoutKind.Sequential)] -internal sealed class Pinnable +public sealed class Pinnable { public byte Data; } diff --git a/MTGOSDK/src/Core/Compiler/Structs/TypeDefToMethod.cs b/MTGOSDK/src/Core/Compiler/Structs/TypeDefToMethod.cs new file mode 100644 index 00000000..5ee3ff53 --- /dev/null +++ b/MTGOSDK/src/Core/Compiler/Structs/TypeDefToMethod.cs @@ -0,0 +1,14 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Compiler.Structs; + +public struct TypeDefToMethod +{ + public ulong MethodTable { get; set; } + public int Token { get; set; } +} diff --git a/MTGOSDK/src/Core/DiagnosticOptions.cs b/MTGOSDK/src/Core/DiagnosticOptions.cs new file mode 100644 index 00000000..87e394bb --- /dev/null +++ b/MTGOSDK/src/Core/DiagnosticOptions.cs @@ -0,0 +1,69 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core; + +/// +/// Configurable options for diagnostic features throughout the SDK. +/// +public struct DiagnosticOptions() +{ + /// + /// Whether to enable logging throughout the SDK. + /// + /// + /// By default, the SDK will use a NullLogger which will not log to any + /// output. To enable logging, provide a logger factory through the + /// method or + /// through the constructor. + /// + /// + /// true to enable logging, false otherwise. + /// + public bool EnableLogging { get; init; } = true; + + /// + /// Whether to enable performance metrics throughout the SDK. + /// + /// + /// Enabling this option will allow the SDK to collect performance metrics + /// throughout its execution. These metrics can be useful for identifying + /// performance bottlenecks and other regression issues between client and + /// SDK versions. + /// + /// + /// true to enable performance metrics, false otherwise. + /// + public bool EnablePerformanceMetrics { get; init; } = false; + + /// + /// Whether to enable snapshot debugging throughout the SDK. + /// + /// + /// As the SDK takes continuous snapshots of the MTGO client, enabling this + /// option will reserve the past few snapshots to inspect previous states of + /// the client. This is managed through the + /// class to + /// provide several copy-on-write snapshots of the client's state. + /// Enabling snapshots can be useful for debugging behaviors intricately + /// dependent on the client's state that are not easily reproducible. + /// + /// + /// true to enable snapshot debugging, false otherwise. + /// + public bool EnableSnapshotDebugging { get; init; } = false; + + /// + /// The interval at which to take snapshots of the client. + /// + /// + /// This option is only relevant if is + /// set to true. The SDK will take a snapshot of the client at the + /// specified interval, allowing for a history of the client's state to be + /// inspected. + /// + public TimeSpan SnapshotInterval { get; init; } = TimeSpan.FromSeconds(30); +} diff --git a/MTGOSDK/src/Core/Remoting/Interop/Exceptions/RemoteException.cs b/MTGOSDK/src/Core/Exceptions/RemoteException.cs similarity index 86% rename from MTGOSDK/src/Core/Remoting/Interop/Exceptions/RemoteException.cs rename to MTGOSDK/src/Core/Exceptions/RemoteException.cs index b530b5d9..c8cff412 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Exceptions/RemoteException.cs +++ b/MTGOSDK/src/Core/Exceptions/RemoteException.cs @@ -1,11 +1,11 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ -namespace MTGOSDK.Core.Remoting.Interop.Exceptions; +namespace MTGOSDK.Core.Exceptions; /// /// Encapsulates an exception that was thrown in the remote object and catched by the Diver. diff --git a/MTGOSDK/src/Core/Exceptions/RemoteObjectMovedException.cs b/MTGOSDK/src/Core/Exceptions/RemoteObjectMovedException.cs new file mode 100644 index 00000000..b682b984 --- /dev/null +++ b/MTGOSDK/src/Core/Exceptions/RemoteObjectMovedException.cs @@ -0,0 +1,14 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Exceptions; + +public class RemoteObjectMovedException(ulong testedAddress, string msg) + : Exception(msg) +{ + public ulong TestedAddress { get; private set; } = testedAddress; +} diff --git a/MTGOSDK/src/Core/Exceptions/SetupFailedException.cs b/MTGOSDK/src/Core/Exceptions/SetupFailureException.cs similarity index 59% rename from MTGOSDK/src/Core/Exceptions/SetupFailedException.cs rename to MTGOSDK/src/Core/Exceptions/SetupFailureException.cs index 05b3e0f8..7e8db676 100644 --- a/MTGOSDK/src/Core/Exceptions/SetupFailedException.cs +++ b/MTGOSDK/src/Core/Exceptions/SetupFailureException.cs @@ -9,13 +9,13 @@ namespace MTGOSDK.Core.Exceptions; /// /// Exception thrown when the setup of the SDK fails. /// -public class SetupFailedException : Exception +public class SetupFailureException : Exception { - public SetupFailedException() { } + public SetupFailureException() { } - public SetupFailedException(string message) + public SetupFailureException(string message) : base(message) { } - public SetupFailedException(string message, Exception inner) + public SetupFailureException(string message, Exception inner) : base(message, inner) { } } diff --git a/MTGOSDK/src/Core/GlobalUsings.cs b/MTGOSDK/src/Core/GlobalUsings.cs new file mode 100644 index 00000000..cb7781b7 --- /dev/null +++ b/MTGOSDK/src/Core/GlobalUsings.cs @@ -0,0 +1,7 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +global using static MTGOSDK.Core.Compiler.Extensions.CallerExtensions; +global using MTGOSDK.Core.Reflection.Attributes; diff --git a/MTGOSDK/src/Core/Logging/Log.cs b/MTGOSDK/src/Core/Logging/Log.cs index 9e72a354..52faf289 100644 --- a/MTGOSDK/src/Core/Logging/Log.cs +++ b/MTGOSDK/src/Core/Logging/Log.cs @@ -14,35 +14,10 @@ namespace MTGOSDK.Core.Logging; /// public class Log : LoggerBase { - private class SuppressionContext : IDisposable - { - private static Type baseType; - - public SuppressionContext(Type callerType, LogLevel logLevel) - { - baseType = GetBaseType(callerType); - s_suppressedCallerTypes.TryAdd(baseType, logLevel); - Debug("Suppressed logging for {type} below loglevel {level}", baseType, logLevel); - } - - public void Dispose() - { - s_suppressedCallerTypes.TryRemove(baseType, out _); - } - } - /// /// Suppresses all logging in the current context. /// - public static IDisposable Suppress() - { - Type callerType; - int depth = 2; - do { callerType = GetCallerType(depth); depth++; } - while (callerType.FullName.StartsWith("System.") || - callerType.FullName.StartsWith("MTGOSDK.Core.Logging.")); - return new SuppressionContext(callerType, LogLevel.None); - } + public static IDisposable Suppress() => new SuppressionContext(LogLevel.None); // // ILogger Extensions diff --git a/MTGOSDK/src/Core/Logging/LogOptionsProvider.cs b/MTGOSDK/src/Core/Logging/LogOptionsProvider.cs index 9f0ce1d8..c4a8843d 100644 --- a/MTGOSDK/src/Core/Logging/LogOptionsProvider.cs +++ b/MTGOSDK/src/Core/Logging/LogOptionsProvider.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using MTGOSDK.Core.Reflection; +using MTGOSDK.Core.Compiler; namespace MTGOSDK.Core.Logging; diff --git a/MTGOSDK/src/Core/Logging/LoggerBase.cs b/MTGOSDK/src/Core/Logging/LoggerBase.cs index cab3868d..7004e276 100644 --- a/MTGOSDK/src/Core/Logging/LoggerBase.cs +++ b/MTGOSDK/src/Core/Logging/LoggerBase.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using MTGOSDK.Core.Compiler.Extensions; using MTGOSDK.Core.Reflection; @@ -47,11 +48,6 @@ public class LoggerBase : DLRWrapper, ILogger /// private static readonly ConcurrentDictionary s_callerTypes = new(); - /// - /// A concurrent bag of caller types that have been suppressed from logging. - /// - internal static readonly ConcurrentDictionary s_suppressedCallerTypes = new(); - /// /// Represents a type used to perform logging. /// @@ -62,7 +58,8 @@ internal static ILogger s_logger { // If logging is suppressed and the caller type is a suppressed type, // return a null logger to prevent logging from suppressed sources. - if (IsSuppressedCallerType()) return s_nulllogger; + if (SuppressionContext.IsSuppressedCallerType()) + return s_nulllogger; // Get the caller type of the calling method or class. Type callerType; @@ -73,10 +70,10 @@ internal static ILogger s_logger // Fetch the base type if the caller is a compiler-generated type // (e.g. lambda expressions, async state machines, etc.). - if (!s_loggers.ContainsKey(callerType) && IsCompilerGenerated(callerType)) + if (!s_loggers.ContainsKey(callerType) && callerType.IsCompilerGenerated()) { if (!s_callerTypes.TryGetValue(callerType, out Type? baseType)) - baseType = GetBaseType(callerType); + baseType = callerType.GetBaseType(); callerType = baseType; } @@ -85,27 +82,6 @@ internal static ILogger s_logger } } - public static bool IsSuppressedCallerType(int depth = 3) - { - if (s_suppressedCallerTypes.Count == 0) - return false; - - // Search the entire call stack for a suppressed caller type. - try - { - for (int i = depth; i < 50; i++) - { - Type callerType = GetCallerType(i); - Type baseType = GetBaseType(callerType); - if (s_suppressedCallerTypes.ContainsKey(callerType)) - return true; - } - } - catch { /* Have fetched past the current depth of the call stack. */ } - - return false; - } - /// /// Creates a logger instance for the given caller type. /// diff --git a/MTGOSDK/src/Core/Logging/SuppressionContext.cs b/MTGOSDK/src/Core/Logging/SuppressionContext.cs new file mode 100644 index 00000000..5c68679b --- /dev/null +++ b/MTGOSDK/src/Core/Logging/SuppressionContext.cs @@ -0,0 +1,75 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System; +using System.Collections.Concurrent; +using Microsoft.Extensions.Logging; + + +using MTGOSDK.Core.Compiler.Extensions; + + +namespace MTGOSDK.Core.Logging; + +/// +/// A class that suppresses logging for a specific caller type. +/// +/// +/// This class creates a context that suppresses all logging invoked from the +/// caller type (and all functions called by the caller type) until the context +/// is disposed. This is useful for suppressing logging for a specific caller +/// type without having to modify the logging configuration or log level. +/// +public class SuppressionContext : IDisposable +{ + private static Type baseType; + + /// + /// A concurrent bag of caller types that have been suppressed from logging. + /// + private static readonly ConcurrentDictionary s_suppressedCallerTypes = new(); + + public SuppressionContext(LogLevel logLevel = LogLevel.None) + { + // Get the type of the original caller creating the suppression context. + Type callerType; + int depth = 3; + do { callerType = GetCallerType(depth); depth++; } + while (callerType.FullName.StartsWith("System.") || + callerType.FullName.StartsWith("MTGOSDK.Core.Logging.")); + + baseType = callerType.GetBaseType(); + s_suppressedCallerTypes.TryAdd(baseType, logLevel); + Log.Debug("Suppressed logging for {type} below loglevel {level}", baseType, logLevel); + } + + public static bool IsSuppressedCallerType() + { + // If there are no suppressed caller types, return false. + if (s_suppressedCallerTypes.Count == 0) + return false; + + // Search the entire call stack for a suppressed caller type. + try + { + int depth = 3; // Default stack depth to begin searching. + for (int i = depth; i < 50; i++) + { + Type callerType = GetCallerType(i); + Type baseType = callerType.GetBaseType(); + if (s_suppressedCallerTypes.ContainsKey(callerType)) + return true; + } + } + catch { /* Have fetched past the current depth of the call stack. */ } + + return false; + } + + public void Dispose() + { + s_suppressedCallerTypes.TryRemove(baseType, out _); + } +} diff --git a/MTGOSDK/src/Core/Reflection/Attributes.cs b/MTGOSDK/src/Core/Reflection/Attributes.cs deleted file mode 100644 index 59c10b82..00000000 --- a/MTGOSDK/src/Core/Reflection/Attributes.cs +++ /dev/null @@ -1,103 +0,0 @@ -/** @file - Copyright (c) 2023, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 -**/ - -using System.Diagnostics; -using System.Reflection; - - -namespace MTGOSDK.Core.Reflection; - -public static class Attributes -{ - // - // Member Attribute Reflection - // - - /// - /// A struct that contains a member and its attribute. - /// - /// The type of attribute. - public struct MemberAttributePair() where T : Attribute - { - public MemberInfo Member { get; init; } - public T Attribute { get; init; } - } - - /// - /// Gets all members of a type that have a specific attribute. - /// - /// The type of attribute. - /// The type to get members from. - /// The binding flags to use. - /// An array of member attribute pairs. - public static MemberAttributePair[] GetMemberAttributes( - this Type type, - BindingFlags bindingFlags = BindingFlags.Public - | BindingFlags.NonPublic - | BindingFlags.Instance - | BindingFlags.Static - | BindingFlags.FlattenHierarchy - ) where T : Attribute => - type.GetMembers(bindingFlags) - .Where(p => p.IsDefined(typeof(T), false)) - .Select(p => new MemberAttributePair() - { - Member = p, -#pragma warning disable CS8601 // Possible null reference argument. - Attribute = p.GetCustomAttributes(typeof(T), false).Single() as T -#pragma warning restore CS8601 - }) - .ToArray(); - - // - // StackFrame Property Reflection - // - - /// - /// Gets the name of the caller. - /// - /// The stack frame depth. - /// The name of the caller. - public static string GetCallerName(int depth) => - new StackFrame(depth).GetMethod().Name - .Replace("get_", "") - .Replace("set_", ""); - - /// - /// Gets the parent type of the caller. - /// - /// The stack frame depth. - /// The type of the caller. - public static Type GetCallerType(int depth) => - new StackFrame(depth).GetMethod().ReflectedType; - - public static MemberAttributePair[] GetMemberAttributes( - int depth = 2 - ) where T : Attribute => - GetCallerType(depth).GetMemberAttributes(); - - /// - /// Gets a specific attribute of the caller, if it exists. - /// - /// The type of attribute. - /// The stack frame depth. - /// The attribute, or null if it does not exist. - public static T? GetCallerAttribute(int depth = 2) where T : Attribute - { - string name = GetCallerName(depth); - try - { - foreach (var memberAttributePair in GetMemberAttributes(depth+1)) - { - if (memberAttributePair.Member.Name == name) - return memberAttributePair.Attribute; - } - } - // Invalid member access (or otherwise doesn't have any attributes) - catch (NullReferenceException) { } - - return null; - } -} diff --git a/MTGOSDK/src/Core/Reflection/Attributes/CallerAttribute.cs b/MTGOSDK/src/Core/Reflection/Attributes/CallerAttribute.cs new file mode 100644 index 00000000..cc1f39f2 --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Attributes/CallerAttribute.cs @@ -0,0 +1,27 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Runtime.CompilerServices; + + +namespace MTGOSDK.Core.Reflection.Attributes; + +/// +/// A wrapper attribute that allows for a default value to fallback to. +/// +/// The default value. +public class CallerAttribute : Attribute where T : Attribute +{ + /// + /// Attempts to get the caller attribute from the outer caller. + /// + /// The caller attribute (if present). + /// True if the caller attribute was found. + public static bool TryGetCallerAttribute(out T? attribute) + { + attribute = GetCallerAttribute(depth: GetCallerDepth()); + return attribute != null; + } +} diff --git a/MTGOSDK/src/Core/Reflection/Attributes/DefaultAttribute.cs b/MTGOSDK/src/Core/Reflection/Attributes/DefaultAttribute.cs new file mode 100644 index 00000000..2a1645d1 --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Attributes/DefaultAttribute.cs @@ -0,0 +1,15 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Reflection.Attributes; +/// +/// A wrapper attribute that allows for a default value to fallback to. +/// +/// The default value. +public class DefaultAttribute(object value) : CallerAttribute +{ + public readonly object Value = value; +} diff --git a/MTGOSDK/src/Core/Reflection/Attributes/MemberAttributePair.cs b/MTGOSDK/src/Core/Reflection/Attributes/MemberAttributePair.cs new file mode 100644 index 00000000..abf6d171 --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Attributes/MemberAttributePair.cs @@ -0,0 +1,20 @@ +/** @file + Copyright (c) 2023, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Diagnostics; +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Attributes; + +/// +/// A struct that contains a member and its attribute. +/// +/// The type of attribute. +public struct MemberAttributePair() where T : Attribute +{ + public MemberInfo Member { get; init; } + public T Attribute { get; init; } +} diff --git a/MTGOSDK/src/Core/Reflection/Attributes/RuntimeInternalAttribute.cs b/MTGOSDK/src/Core/Reflection/Attributes/RuntimeInternalAttribute.cs new file mode 100644 index 00000000..f00055b1 --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Attributes/RuntimeInternalAttribute.cs @@ -0,0 +1,17 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Reflection.Attributes; + +/// +/// A wrapper attribute that indicates that a field is internal to the runtime. +/// +/// The default value. +public class RuntimeInternalAttribute(Type? baseType = null) + : CallerAttribute +{ + public readonly Type BaseType = baseType ?? typeof(object); +} diff --git a/MTGOSDK/src/Core/Reflection/DLRWrapper.cs b/MTGOSDK/src/Core/Reflection/DLRWrapper.cs index 7a637160..34c82850 100644 --- a/MTGOSDK/src/Core/Reflection/DLRWrapper.cs +++ b/MTGOSDK/src/Core/Reflection/DLRWrapper.cs @@ -9,12 +9,15 @@ using System.Reflection; using System.Runtime.CompilerServices; +using MTGOSDK.Core.Compiler; +using MTGOSDK.Core.Compiler.Extensions; using MTGOSDK.Core.Logging; +using MTGOSDK.Core.Reflection.Attributes; +using MTGOSDK.Core.Reflection.Extensions; using MTGOSDK.Core.Remoting; namespace MTGOSDK.Core.Reflection; -using static Attributes; /// /// A wrapper for dynamic objects that implement an interface at runtime. @@ -61,6 +64,10 @@ public DLRWrapper(Func? factory = null) : this() if (factory != null) factory.Invoke().Wait(); } + // + // Internal fields and properties for the wrapped object. + // + /// /// The internal reference for the binding type for the wrapped object. /// @@ -94,10 +101,10 @@ internal virtual dynamic @base // Attempt to extract the base object from the derived class. var baseObj = Try(() => obj is DLRWrapper ? obj.obj : obj); - // Return a ProxyObject wrapper with a default value, if present. - if (TryGetDefaultAttribute(out var defaultAttribute)) + // Return a DynamicProxy wrapper with a default value, if present. + if (DefaultAttribute.TryGetCallerAttribute(out var defaultAttribute)) { - return new ProxyObject(baseObj, @default: defaultAttribute.Value); + return new DynamicProxy(baseObj, @default: defaultAttribute.Value); } else if (baseObj is null) { @@ -109,43 +116,6 @@ internal virtual dynamic @base } } - /// - /// Marks the retrieval of a DLRWrapper's instance as optional. - /// - /// The class type to instantiate. - /// The object to wrap. - /// The condition to check before wrapping. - /// The wrapped object or null if the object is null. - public static T? Optional( - dynamic obj, - Func condition = null) where T : class - { - // Return null if the condition is not met - if (condition != null && !condition(obj)) - return null; - - // Return null if the underlying object is null - if (Try(() => (obj == null || Unbind(obj) == null))) - return null; - - if (typeof(T).IsSubclassOf(typeof(DLRWrapper))) - return (T)(InstanceFactory.CreateInstance(typeof(T), obj)); - else - return Cast(obj); - } - - /// - /// Marks the retrieval of a DLRWrapper's instance as optional. - /// - /// The class type to instantiate. - /// The object to wrap. - /// The condition to check before wrapping. - /// The wrapped object or null if the object is null. - public static T? Optional(dynamic obj, bool condition) where T : class - { - return Optional(obj, new Func(_ => condition)); - } - // // Wrapper methods for type casting and dynamic dispatching. // @@ -161,7 +131,7 @@ internal virtual dynamic @base /// public static T Bind(dynamic obj) where T : class { - return Proxy.As(obj) + return TypeProxy.As(obj) ?? throw new InvalidOperationException( $"Unable to bind {obj.GetType().Name} to {typeof(T).Name}."); } @@ -176,15 +146,16 @@ public static T Bind(dynamic obj) where T : class /// public static dynamic Unbind(dynamic obj) { - Func isProxy = (o) => o.GetType().Name.StartsWith("ActLike_"); - if (!isProxy(obj)) return obj; + if (!TypeProxy.IsProxy(obj)) + return obj; - var unbound_obj = Proxy.From(obj) + var unbound_obj = TypeProxy.From(obj) ?? throw new InvalidOperationException( $"Unable to unbind types from {obj.GetType().Name}."); // Recursively unbind any nested interface types. - if (isProxy(unbound_obj)) return Unbind(unbound_obj); + if (TypeProxy.IsProxy(unbound_obj)) + return Unbind(unbound_obj); return unbound_obj; } @@ -260,7 +231,7 @@ public static T Cast(dynamic obj) /// /// Provides a default type mapper based on the given reference type. /// - private static dynamic UseTypeMapper() + internal static dynamic UseTypeMapper() where T1 : notnull where T2 : notnull { @@ -324,18 +295,15 @@ public static IEnumerable Map(dynamic obj, Func? func = null) /// The item type to cast to. /// The object or enumerable to iterate over. /// The function to run for each item (optional). + /// Whether to return a proxy instance (optional). /// A list of the function's output. - public static IList Map(dynamic obj, Func? func = null) - where L : IList - where T : notnull + public static IList Map( + dynamic obj, + Func? func = null, + bool proxy = false) + where L : IList + where T : notnull { - IList newList = Try( - // Attempt to create a new instance of the 'L' list type. - () => InstanceFactory.CreateInstance(typeof(L)), - // Otherwise fallback to a generic list implementation - // (i.e. when the provided type is abstract or has no constructor). - () => new List()); - dynamic innerList = Try( // Attempt to cast the object to a list type. () => Cast(obj), @@ -343,6 +311,26 @@ public static IList Map(dynamic obj, Func? func = null) // Otherwise fallback to a dynamic list implementation. () => obj as dynamic); + // // If `T` is a DLRWrapper type and the object is a dynamic remote object, + // // then simply return a ListProxy instance wrapping the remote list object. + // if (typeof(T).IsOpenSubtypeOf(typeof(DLRWrapper<>))) + // { + // IList proxy = new ListProxyinnerList, func); + // + // // If the instance has a well-defined count property, return the instance. + // if (Try(() => proxy.Count >= 0)) + // return proxy; + // } + if (proxy) return new ListProxy(innerList, func); + + // Otherwise allocate a local list object and map the items to the new type. + IList newList = Try( + // Attempt to create a new instance of the 'L' list type. + () => InstanceFactory.CreateInstance(typeof(L)), + // Otherwise fallback to a generic list implementation + // (i.e. when the provided type is abstract or has no constructor). + () => new List()); + foreach (var item in Map(innerList, func)) newList.Add(item); return newList; } @@ -453,80 +441,40 @@ public static T Retry( } } - // - // Wrapper Attributes - // - - /// - /// A wrapper attribute that allows for a default value to fallback to. - /// - /// The default value. - public class DefaultAttribute(object value) : Attribute - { - public object Value { get; set; } = value; - } - /// - /// Determines whether the type is compiler-generated. - /// - public static bool IsCompilerGenerated(Type t) - { - if (t == null) return false; - - return t.IsDefined(typeof(CompilerGeneratedAttribute), false) - || IsCompilerGenerated(t.DeclaringType); - } - - // - // Attribute wrapper helpers. - // - - /// - /// Extracts the base type from a compiler-generated type. + /// Marks the retrieval of a DLRWrapper's instance as optional. /// - /// The type to extract the base type from. - /// The base type of the given type. - public static Type GetBaseType(Type callerType) + /// The class type to instantiate. + /// The object to wrap. + /// The condition to check before wrapping. + /// The wrapped object or null if the object is null. + public static T? Optional( + dynamic obj, + Func condition = null) where T : class { - if (!IsCompilerGenerated(callerType)) - return callerType; - - string fullName = callerType.FullName; - string baseName = fullName.Substring(0, fullName.IndexOf("+<")); - Type baseType = callerType.DeclaringType.Assembly.GetType(baseName); - - return baseType; - } - - /// - /// Gets the parent type of the caller. - /// - /// The stack frame depth. - /// The type of the caller. - public static Type GetCallerType(int depth = 4) => - new StackFrame(depth).GetMethod().ReflectedType; + // Return null if the condition is not met + if (condition != null && !condition(obj)) + return null; - /// - /// Gets the stack frame depth of the (outer) DLRWrapper caller. - /// - /// The starting stack frame depth. - /// The caller's stack frame depth. - private static int GetCallerDepth(int depth = 3) - { - Type wrapperType = GetCallerType(depth); - while(GetCallerType(depth).Name == wrapperType.Name && depth < 50) depth++; + // Return null if the underlying object is null + if (Try(() => (obj == null || Unbind(obj) == null))) + return null; - return depth; + if (typeof(T).IsSubclassOf(typeof(DLRWrapper))) + return (T)(InstanceFactory.CreateInstance(typeof(T), obj)); + else + return Cast(obj); } /// - /// Attempts to get the default attribute from the (outer) DLRWrapper caller. + /// Marks the retrieval of a DLRWrapper's instance as optional. /// - /// The default attribute (if present). - /// True if the default attribute was found. - private static bool TryGetDefaultAttribute(out DefaultAttribute? attribute) + /// The class type to instantiate. + /// The object to wrap. + /// The condition to check before wrapping. + /// The wrapped object or null if the object is null. + public static T? Optional(dynamic obj, bool condition) where T : class { - attribute = GetCallerAttribute(depth: GetCallerDepth()); - return attribute != null; + return Optional(obj, new Func(_ => condition)); } } diff --git a/MTGOSDK/src/Core/Reflection/ProxyObject.cs b/MTGOSDK/src/Core/Reflection/DynamicProxy.cs similarity index 98% rename from MTGOSDK/src/Core/Reflection/ProxyObject.cs rename to MTGOSDK/src/Core/Reflection/DynamicProxy.cs index cab04974..3f876e0d 100644 --- a/MTGOSDK/src/Core/Reflection/ProxyObject.cs +++ b/MTGOSDK/src/Core/Reflection/DynamicProxy.cs @@ -13,7 +13,7 @@ namespace MTGOSDK.Core.Reflection; /// /// Provides a dynamic object that can be used to wrap a static value. /// -public class ProxyObject( +public class DynamicProxy( dynamic @base, dynamic @default = null, dynamic fallback = null, diff --git a/MTGOSDK/src/Core/Remoting/Internal/Utils/MethodBaseExtensions.cs b/MTGOSDK/src/Core/Reflection/Extensions/MethodBaseExtensions.cs similarity index 95% rename from MTGOSDK/src/Core/Remoting/Internal/Utils/MethodBaseExtensions.cs rename to MTGOSDK/src/Core/Reflection/Extensions/MethodBaseExtensions.cs index 9f61cf27..74327710 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Utils/MethodBaseExtensions.cs +++ b/MTGOSDK/src/Core/Reflection/Extensions/MethodBaseExtensions.cs @@ -1,13 +1,13 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Reflection; -namespace MTGOSDK.Core.Remoting.Internal.Utils; +namespace MTGOSDK.Core.Reflection.Extensions; public static class MethodBaseExtensions { diff --git a/MTGOSDK/src/Core/Remoting/Interop/Utils/TypeExt.cs b/MTGOSDK/src/Core/Reflection/Extensions/TypeExtensions.cs similarity index 72% rename from MTGOSDK/src/Core/Remoting/Interop/Utils/TypeExt.cs rename to MTGOSDK/src/Core/Reflection/Extensions/TypeExtensions.cs index 97bbd980..b5f2413b 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Utils/TypeExt.cs +++ b/MTGOSDK/src/Core/Reflection/Extensions/TypeExtensions.cs @@ -1,31 +1,46 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Reflection; -using MTGOSDK.Core.Remoting.Interop.Extensions; +using MTGOSDK.Core.Reflection.Attributes; +using MTGOSDK.Core.Reflection.Types; -namespace MTGOSDK.Core.Remoting.Interop.Utils; +namespace MTGOSDK.Core.Reflection.Extensions; -public static class TypeExt +public static class TypeExtensions { - public class WildCardEnabledTypesComparer : IEqualityComparer - { - public bool Equals(Type x, Type y) - { - if (x is WildCardType || y is WildCardType) - return true; - return x.IsAssignableFrom(y); - } - - public int GetHashCode(Type obj) => obj.GetHashCode(); - } + private static readonly TypeComparer _wildCardTypesComparer = new(); - private static readonly WildCardEnabledTypesComparer _wildCardTypesComparer = new(); + /// + /// Gets all members of a type that have a specific attribute. + /// + /// The type of attribute. + /// The type to get members from. + /// The binding flags to use. + /// An array of member attribute pairs. + public static MemberAttributePair[] GetMemberAttributes( + this Type type, + BindingFlags bindingFlags = BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.Instance + | BindingFlags.Static + | BindingFlags.FlattenHierarchy + ) where T : Attribute => + type.GetMembers(bindingFlags) + .Where(p => p.IsDefined(typeof(T), false)) + .Select(p => new MemberAttributePair() + { + Member = p, +#pragma warning disable CS8601 // Possible null reference argument. + Attribute = p.GetCustomAttributes(typeof(T), false).Single() as T +#pragma warning restore CS8601 + }) + .ToArray(); /// /// Searches a type for a specific method. If not found searches its ancestors. @@ -132,7 +147,7 @@ public static ConstructorInfo GetConstructor( m.GetParameters() .Select(pi => pi.ParameterType) .SequenceEqual(parameterTypes, - new TypeExt.WildCardEnabledTypesComparer())); + new TypeComparer())); } return ctorInfo; @@ -186,12 +201,29 @@ public static bool IsStringCoercible(this Type realType) public static Type GetType(this AppDomain domain, string typeFullName) { var assemblies = domain.GetAssemblies(); - foreach (Assembly assm in assemblies) + foreach (Assembly asm in assemblies) { - Type t = assm.GetType(typeFullName); - if (t != null) - return t; + Type t = asm.GetType(typeFullName); + if (t != null) return t; } return null; } + + /// + /// Determines if a type is a subtype of another open generic type. + /// + /// The type to check. + /// The open generic type to check against. + /// True if the type is a subtype of the open generic type. + public static bool IsOpenSubtypeOf(this Type type, Type baseType) + { + try + { + return type.BaseType.GetGenericTypeDefinition().IsAssignableFrom(baseType); + } + catch + { + return false; + } + } } diff --git a/MTGOSDK/src/Core/Reflection/ListProxy.cs b/MTGOSDK/src/Core/Reflection/ListProxy.cs new file mode 100644 index 00000000..df9fd44f --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/ListProxy.cs @@ -0,0 +1,75 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Collections; +using System.Collections.Generic; + + +namespace MTGOSDK.Core.Reflection; + +/// +/// Represents a proxy object for a remote list object. +/// +public class ListProxy( + dynamic list, + Func? func = null) + : DLRWrapper>, IList where T : notnull +{ + /// + /// Stores an internal reference to the remote list object. + /// + internal override dynamic obj => Bind(list); + + private dynamic s_typeMapper = func ?? UseTypeMapper(); + + // + // IList wrapper properties + // + + public int Count => @base.Count; + + public bool IsReadOnly => @base.IsReadOnly; + + public T this[int index] + { + get => s_typeMapper(Unbind(@base)[index]); + set => Unbind(@base)[index] = value; + } + + // + // IList wrapper methods + // + + public void Add(T item) => @base.Add(item); + + public void Clear() => @base.Clear(); + + public bool Contains(T item) => @base.Contains(item); + + public void CopyTo(T[] array, int arrayIndex) + { + var baseRef = Unbind(@base); + for (int i = 0; i < this.Count; i++) + { + array[arrayIndex + i] = s_typeMapper(baseRef[i]); + } + } + + public IEnumerator GetEnumerator() => Map(@base, func); + + public int IndexOf(T item) => @base.IndexOf(item); + + public void Insert(int index, T item) => @base.Insert(index, item); + + public bool Remove(T item) => @base.Remove(item); + + public void RemoveAt(int index) => @base.RemoveAt(index); + + // + // IEnumerable wrapper methods + // + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/MTGOSDK/src/Core/Reflection/Proxy.cs b/MTGOSDK/src/Core/Reflection/TypeProxy.cs similarity index 87% rename from MTGOSDK/src/Core/Reflection/Proxy.cs rename to MTGOSDK/src/Core/Reflection/TypeProxy.cs index 5d82d8bd..e527391e 100644 --- a/MTGOSDK/src/Core/Reflection/Proxy.cs +++ b/MTGOSDK/src/Core/Reflection/TypeProxy.cs @@ -8,7 +8,7 @@ namespace MTGOSDK.Core.Reflection; -public class Proxy(Type? @type=null) where T : class +public class TypeProxy(Type? @type=null) where T : class { // // BuilderProxy methods @@ -43,6 +43,14 @@ public static dynamic As(dynamic? obj=null, params Type[] interfaces) => public static dynamic From(dynamic? obj=null) => Impromptu.UndoActLike(obj); + /// + /// Check whether an instance implements a proxy interface. + /// + /// The object to check + /// True if the object is a proxy + public static bool IsProxy(dynamic? obj=null) => + typeof(IActLikeProxy).IsAssignableFrom(obj.GetType()); + // // Derived class properties // @@ -102,6 +110,6 @@ public override string ToString() => Class.FullName ?? throw new TypeInitializationException( $"The Proxied type is not a valid type.", innerException: null); - public static implicit operator string(Proxy proxy) => + public static implicit operator string(TypeProxy proxy) => proxy.ToString(); } diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/TypesResolver.cs b/MTGOSDK/src/Core/Reflection/TypeResolver.cs similarity index 78% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/TypesResolver.cs rename to MTGOSDK/src/Core/Reflection/TypeResolver.cs index 3d9f1e44..390537d4 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/TypesResolver.cs +++ b/MTGOSDK/src/Core/Reflection/TypeResolver.cs @@ -1,25 +1,27 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Reflection; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; + +namespace MTGOSDK.Core.Reflection; /// /// Resolves local and remote types. Contains a cache so the same TypeFullName /// object is returned for different resolutions for the same remote type. /// -public class TypesResolver() +public class TypeResolver() { + private readonly Dictionary, Type> _cache = new(); + // Since the resolver works with a cache that should be global we make the // whole class a singleton - public static TypesResolver Instance = new TypesResolver(); - - internal readonly Dictionary, Type> _cache = new(); + public static TypeResolver Instance = new TypeResolver(); public void RegisterType(Type type) => RegisterType(type.Assembly.GetName().Name, type.FullName, type); @@ -44,8 +46,9 @@ public Type Resolve(string assemblyName, string typeFullName) // Filter assemblies but avoid filtering for "mscorlib" if(assemblyName?.Equals("mscorlib") == false) { - assemblies = assemblies.Where(assm => assm.FullName.Contains(assemblyName ?? "")); + assemblies = assemblies.Where(asm => asm.FullName.Contains(assemblyName ?? "")); } + foreach (Assembly assembly in assemblies) { resolvedType = assembly.GetType(typeFullName); @@ -53,10 +56,7 @@ public Type Resolve(string assemblyName, string typeFullName) { // Found the type! // But retreat if it's an enum (and get remote proxy of it instead) - if(resolvedType.IsEnum) - { - resolvedType = null; - } + if(resolvedType.IsEnum) resolvedType = null; break; } } @@ -68,4 +68,9 @@ public Type Resolve(string assemblyName, string typeFullName) return resolvedType; } + + public void ClearCache() + { + _cache.Clear(); + } } diff --git a/MTGOSDK/src/Core/Reflection/Types/ConstructorInfoStub.cs b/MTGOSDK/src/Core/Reflection/Types/ConstructorInfoStub.cs new file mode 100644 index 00000000..6533b218 --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Types/ConstructorInfoStub.cs @@ -0,0 +1,69 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Globalization; +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Types; + +public class ConstructorInfoStub : ConstructorInfo +{ + public override string Name => throw new NotImplementedException(); + public override Type DeclaringType => throw new NotImplementedException(); + public override Type ReflectedType => throw new NotImplementedException(); + + public override MethodAttributes Attributes => + throw new NotImplementedException(); + + public override RuntimeMethodHandle MethodHandle => + throw new NotImplementedException(); + public override object[] GetCustomAttributes(bool inherit) + { + throw new NotImplementedException(); + } + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override MethodImplAttributes GetMethodImplementationFlags() + { + throw new NotImplementedException(); + } + + public override ParameterInfo[] GetParameters() => + throw new NotImplementedException(); + + public override object Invoke( + BindingFlags invokeAttr, + Binder binder, + object[] parameters, + CultureInfo culture) + { + throw new NotImplementedException(); + } + + public override object Invoke( + object obj, + BindingFlags invokeAttr, + Binder binder, + object[] parameters, + CultureInfo culture) + { + throw new NotImplementedException(); + } + + public override bool IsDefined(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override string ToString() + { + throw new NotImplementedException(); + } +} diff --git a/MTGOSDK/src/Core/Reflection/Types/FieldInfoStub.cs b/MTGOSDK/src/Core/Reflection/Types/FieldInfoStub.cs new file mode 100644 index 00000000..cb24e19e --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Types/FieldInfoStub.cs @@ -0,0 +1,52 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Globalization; +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Types; + +public class FieldInfoStub : FieldInfo +{ + public override string Name => throw new NotImplementedException(); + public override Type FieldType => throw new NotImplementedException(); + public override Type DeclaringType => throw new NotImplementedException(); + public override Type ReflectedType => throw new NotImplementedException(); + public override FieldAttributes Attributes => throw new NotImplementedException(); + public override RuntimeFieldHandle FieldHandle => throw new NotImplementedException(); + + public override object[] GetCustomAttributes(bool inherit) + { + throw new NotImplementedException(); + } + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override bool IsDefined(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override object GetValue(object obj) + { + throw new NotImplementedException(); + } + + public override void SetValue( + object obj, + object value, + BindingFlags invokeAttr, + Binder binder, + CultureInfo culture) + { + throw new NotImplementedException(); + } + + public override string ToString() => throw new NotImplementedException(); +} diff --git a/MTGOSDK/src/Core/Reflection/Types/MethodInfoStub.cs b/MTGOSDK/src/Core/Reflection/Types/MethodInfoStub.cs new file mode 100644 index 00000000..38c89ac3 --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Types/MethodInfoStub.cs @@ -0,0 +1,98 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Globalization; +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Types; + +public class MethodInfoStub : MethodInfo +{ + public override string Name => + throw new NotImplementedException(); + + public override Type DeclaringType => + throw new NotImplementedException(); + + public override Type ReturnType => + throw new NotImplementedException(); + + public override Type ReflectedType => + throw new NotImplementedException(); + + public override RuntimeMethodHandle MethodHandle => + throw new NotImplementedException(); + + public override MethodAttributes Attributes => + throw new NotImplementedException(); + + public override ICustomAttributeProvider ReturnTypeCustomAttributes => + throw new NotImplementedException(); + + public override bool IsGenericMethod => + throw new NotImplementedException(); + + public override bool IsGenericMethodDefinition => + throw new NotImplementedException(); + + public override bool ContainsGenericParameters => + throw new NotImplementedException(); + + public override Type[] GetGenericArguments() + { + throw new NotImplementedException(); + } + + public override MethodInfo MakeGenericMethod(params Type[] typeArguments) + { + throw new NotImplementedException(); + } + + public override object[] GetCustomAttributes(bool inherit) + { + throw new NotImplementedException(); + } + + public override bool IsDefined(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override ParameterInfo[] GetParameters() + { + throw new NotImplementedException(); + } + + public override MethodImplAttributes GetMethodImplementationFlags() + { + throw new NotImplementedException(); + } + + public override object Invoke( + object obj, + BindingFlags invokeAttr, + Binder binder, + object[] parameters, + CultureInfo culture) + { + throw new NotImplementedException(); + } + + public override MethodInfo GetBaseDefinition() + { + throw new NotImplementedException(); + } + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override string ToString() + { + throw new NotImplementedException(); + } +} diff --git a/MTGOSDK/src/Core/Reflection/Types/ParameterInfoStub.cs b/MTGOSDK/src/Core/Reflection/Types/ParameterInfoStub.cs new file mode 100644 index 00000000..79d6613d --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Types/ParameterInfoStub.cs @@ -0,0 +1,18 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Types; + +public class ParameterInfoStub : ParameterInfo +{ + public override string Name => throw new NotImplementedException(); + + public override Type ParameterType => throw new NotImplementedException(); + + public override string ToString() => throw new NotImplementedException(); +} diff --git a/MTGOSDK/src/Core/Reflection/Types/PropertyInfoStub.cs b/MTGOSDK/src/Core/Reflection/Types/PropertyInfoStub.cs new file mode 100644 index 00000000..f1ad0f3f --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Types/PropertyInfoStub.cs @@ -0,0 +1,91 @@ +/** @file + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Globalization; +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Types; + +public class PropertyInfoStub : PropertyInfo +{ + public override string Name => + throw new NotImplementedException(); + + public override Type DeclaringType => + throw new NotImplementedException(); + + public override Type PropertyType => + throw new NotImplementedException(); + + public override PropertyAttributes Attributes => + throw new NotImplementedException(); + + public override Type ReflectedType => throw new NotImplementedException(); + + public override MethodInfo GetMethod => throw new NotImplementedException(); + public override MethodInfo SetMethod => throw new NotImplementedException(); + + public override bool CanRead => throw new NotImplementedException(); + public override bool CanWrite => throw new NotImplementedException(); + + public override MethodInfo[] GetAccessors(bool nonPublic) + { + throw new NotImplementedException(); + } + + public override object[] GetCustomAttributes(bool inherit) + { + throw new NotImplementedException(); + } + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override MethodInfo GetGetMethod(bool nonPublic) + { + throw new NotImplementedException(); + } + + public override MethodInfo GetSetMethod(bool nonPublic) + { + throw new NotImplementedException(); + } + + public override ParameterInfo[] GetIndexParameters() + { + throw new NotImplementedException(); + } + + public override object GetValue( + object obj, + BindingFlags invokeAttr, + Binder binder, + object[] index, + CultureInfo culture) + { + throw new NotImplementedException(); + } + + public override bool IsDefined(Type attributeType, bool inherit) + { + throw new NotImplementedException(); + } + + public override void SetValue( + object obj, + object value, + BindingFlags invokeAttr, + Binder binder, + object[] index, + CultureInfo culture) + { + throw new NotImplementedException(); + } + + public override string ToString() => throw new NotImplementedException(); +} diff --git a/MTGOSDK/src/Core/Reflection/Types/TypeComparer.cs b/MTGOSDK/src/Core/Reflection/Types/TypeComparer.cs new file mode 100644 index 00000000..46e4b18e --- /dev/null +++ b/MTGOSDK/src/Core/Reflection/Types/TypeComparer.cs @@ -0,0 +1,22 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Reflection; + + +namespace MTGOSDK.Core.Reflection.Types; + +public class TypeComparer : IEqualityComparer +{ + public bool Equals(Type x, Type y) + { + if (x is TypeStub || y is TypeStub) + return true; + return x.IsAssignableFrom(y); + } + + public int GetHashCode(Type obj) => obj.GetHashCode(); +} diff --git a/MTGOSDK/src/Core/Remoting/Interop/Extensions/WildCardType.cs b/MTGOSDK/src/Core/Reflection/Types/TypeStub.cs similarity index 80% rename from MTGOSDK/src/Core/Remoting/Interop/Extensions/WildCardType.cs rename to MTGOSDK/src/Core/Reflection/Types/TypeStub.cs index cda2f086..68c9daf8 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Extensions/WildCardType.cs +++ b/MTGOSDK/src/Core/Reflection/Types/TypeStub.cs @@ -1,20 +1,35 @@ -/** @file - Copyright (c) 2021, Xappy. +/** @file Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Globalization; using System.Reflection; -namespace MTGOSDK.Core.Remoting.Interop.Extensions; +namespace MTGOSDK.Core.Reflection.Types; -/// -/// This fake type is used when the type of a parameter is unknown (if NULL was passed) -/// -public class WildCardType : Type +public class TypeStub( + string name = nameof(TypeStub), + Guid guid = default, + Module module = default, + Assembly assembly = default, + string fullName = default, + string @namespace = default, + string assemblyQualifiedName = default, + Type baseType = default, + Type underlyingSystemType = default) : Type { + public override string Name => name; + public override Guid GUID => guid; + public override Module Module => module; + public override Assembly Assembly => assembly; + public override string FullName => fullName; + public override string Namespace => @namespace; + public override string AssemblyQualifiedName => assemblyQualifiedName; + public override Type BaseType => baseType; + public override Type UnderlyingSystemType => underlyingSystemType; + public override object[] GetCustomAttributes(bool inherit) { throw new NotImplementedException(); @@ -160,8 +175,6 @@ public override object InvokeMember( throw new NotImplementedException(); } - public override Type UnderlyingSystemType { get; } - protected override ConstructorInfo GetConstructorImpl( BindingFlags bindingAttr, Binder binder, @@ -172,15 +185,6 @@ protected override ConstructorInfo GetConstructorImpl( throw new NotImplementedException(); } - public override string Name { get; } - public override Guid GUID { get; } - public override Module Module { get; } - public override Assembly Assembly { get; } - public override string FullName { get; } - public override string Namespace { get; } - public override string AssemblyQualifiedName { get; } - public override Type BaseType { get; } - public override object[] GetCustomAttributes(Type attributeType, bool inherit) { throw new NotImplementedException(); diff --git a/MTGOSDK/src/Core/Remoting/CandidateObject.cs b/MTGOSDK/src/Core/Remoting/CandidateObject.cs deleted file mode 100644 index 28268e2e..00000000 --- a/MTGOSDK/src/Core/Remoting/CandidateObject.cs +++ /dev/null @@ -1,19 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - - -namespace MTGOSDK.Core.Remoting; - -/// -/// A candidate for a remote object. -/// Holding this item does not mean having a meaningful hold of the remote object. To gain one use -/// -public struct CandidateObject(ulong address, string typeFullName, int hashCode) -{ - public ulong Address = address; - public string TypeFullName = typeFullName; - public int HashCode = hashCode; -} diff --git a/MTGOSDK/src/Core/Remoting/CandidateType.cs b/MTGOSDK/src/Core/Remoting/CandidateType.cs deleted file mode 100644 index 11bfa1b6..00000000 --- a/MTGOSDK/src/Core/Remoting/CandidateType.cs +++ /dev/null @@ -1,14 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - - -namespace MTGOSDK.Core.Remoting; - -public struct CandidateType(string typeName, string assembly) -{ - public string TypeFullName = typeName; - public string Assembly = assembly; -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/DiverDiscovery.cs b/MTGOSDK/src/Core/Remoting/Internal/DiverDiscovery.cs deleted file mode 100644 index 5556462d..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/DiverDiscovery.cs +++ /dev/null @@ -1,83 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; - -using MTGOSDK.Core.Remoting.Interop; - -using MTGOSDK.Win32.Extensions; - - -namespace MTGOSDK.Core.Remoting.Internal; - -public enum DiverState -{ - NoDiver, - Alive, - Corpse, - HollowSnapshot -} - -public static class DiverDiscovery -{ - public static DiverState QueryStatus( - Process target, - string diverAddr, - ushort diverPort) - { - DiverCommunicator com = new DiverCommunicator(diverAddr, diverPort); - - // We WANT to check liveness of the diver using HTTP but this might take a - // LOT of time if it is dead (Trying to TCP SYN several times, with a - // timeout between each). So a simple circuit-breaker is implemented - // before that: If we manage to bind to the expected diver endpoint, we - // assume it's not alive - - bool diverPortIsFree = false; - try - { - IPAddress localAddr = IPAddress.Parse(diverAddr); - TcpListener server = new TcpListener(localAddr, diverPort); - server.Start(); - diverPortIsFree = true; - server.Stop(); - } - catch - { - // Had some issues, perhaps it's the diver holding that port. - } - - if (!diverPortIsFree && com.CheckAliveness()) - { - return DiverState.Alive; - } - - // // Check if this is a snapshot created by the diver. - // if (target.Threads.Count == 0) - // return DiverState.HollowSnapshot; - - // Diver isn't alive. It's possible that it was never injected or it was - // injected and killed - bool containsToolkitDll = false; - try - { - containsToolkitDll |= target.Modules.AsEnumerable() - .Any(module => module.ModuleName.Contains("Bootstrapper")); - } - catch - { - // Sometimes this happens because of x32 vs x64 process interaction - } - if (containsToolkitDll) - { - return DiverState.Corpse; - } - - return DiverState.NoDiver; - } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteObjectFactory.cs b/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteObjectFactory.cs deleted file mode 100644 index 2128c418..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteObjectFactory.cs +++ /dev/null @@ -1,24 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; - - -namespace MTGOSDK.Core.Remoting.Internal; - -public class DynamicRemoteObjectFactory -{ - private RemoteHandle _app; - - public DynamicRemoteObject Create( - RemoteHandle rApp, - RemoteObject remoteObj, - TypeDump typeDump) - { - _app = rApp; - return new DynamicRemoteObject(rApp, remoteObj); - } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/IProxiedMember.cs b/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/IProxiedMember.cs deleted file mode 100644 index f0bf988f..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/IProxiedMember.cs +++ /dev/null @@ -1,12 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -namespace MTGOSDK.Core.Remoting.Internal.ProxiedReflection; - -public interface IProxiedMember -{ - public ProxiedMemberType Type { get; } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedEventInfo.cs b/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedEventInfo.cs deleted file mode 100644 index baab496b..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedEventInfo.cs +++ /dev/null @@ -1,46 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using System.Reflection; - - -namespace MTGOSDK.Core.Remoting.Internal.ProxiedReflection; - -public class ProxiedEventInfo(RemoteObject ro, string name, List args) - : IProxiedMember -{ - public ProxiedMemberType Type => ProxiedMemberType.Event; - - private readonly RemoteObject _ro = ro; - private string Name { get; set; } = name; - private List ArgumentsTypes { get; set; } = args; - - public static ProxiedEventInfo operator +(ProxiedEventInfo c1, Delegate x) - { - ParameterInfo[] parameters = x.Method.GetParameters(); - - if (parameters.Length != c1.ArgumentsTypes.Count) - { - throw new Exception($"The '{c1.Name}' event expects {c1.ArgumentsTypes.Count} parameters, " + - $"the callback that was being registered have {parameters.Length}"); - } - - if (parameters.Any(p => p.GetType().IsAssignableFrom(typeof(DynamicRemoteObject)))) - { - throw new Exception("A Remote event's local callback must have only 'dynamic' parameters"); - } - - c1._ro.EventSubscribe(c1.Name, x); - - return c1; - } - - public static ProxiedEventInfo operator -(ProxiedEventInfo c1, Delegate x) - { - c1._ro.EventUnsubscribe(c1.Name, x); - return c1; - } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMemberType.cs b/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMemberType.cs deleted file mode 100644 index ead0b9e4..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMemberType.cs +++ /dev/null @@ -1,16 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -namespace MTGOSDK.Core.Remoting.Internal.ProxiedReflection; - -public enum ProxiedMemberType -{ - Unknown, - Field, - Property, - Method, - Event -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMethodGroup.cs b/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMethodGroup.cs deleted file mode 100644 index 211e350a..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMethodGroup.cs +++ /dev/null @@ -1,13 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using MTGOSDK.Core.Remoting.Internal.Reflection; - - -namespace MTGOSDK.Core.Remoting.Internal.ProxiedReflection; - -public class ProxiedMethodGroup : List -{ } diff --git a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMethodOverload.cs b/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMethodOverload.cs deleted file mode 100644 index 10a5f53f..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedMethodOverload.cs +++ /dev/null @@ -1,20 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using MTGOSDK.Core.Remoting.Internal.Reflection; - - -namespace MTGOSDK.Core.Remoting.Internal.ProxiedReflection; - -public class ProxiedMethodOverload -{ - public Type ReturnType { get; set; } - public List Parameters { get; set; } - public Func Proxy => (object[] arr) => GenericProxy(null, arr); - public Func GenericProxy { get; set; } - public List GenericArgs { get; set; } - public bool IsGenericMethod => GenericArgs?.Count > 0; -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedValueMemberInfo.cs b/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedValueMemberInfo.cs deleted file mode 100644 index 353821b4..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/ProxiedReflection/ProxiedValueMemberInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - - -namespace MTGOSDK.Core.Remoting.Internal.ProxiedReflection; - -/// -/// Info of proxied field or property -/// -public class ProxiedValueMemberInfo(ProxiedMemberType type) : IProxiedMember -{ - public string FullTypeName { get; set; } - public Action Setter { get; set; } - public Func Getter { get; set; } - - public ProxiedMemberType Type { get; set; } = type; -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/DummyGenericType.cs b/MTGOSDK/src/Core/Remoting/Internal/Reflection/DummyGenericType.cs deleted file mode 100644 index 8dfb0ae7..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/DummyGenericType.cs +++ /dev/null @@ -1,186 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using System.Globalization; -using System.Reflection; - - -namespace MTGOSDK.Core.Remoting.Internal.Reflection; - -public class DummyGenericType(string name) : Type -{ - public override Module Module { get; } - public override string Namespace { get; } - - public override string Name => name; - - public override object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - public override bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - protected override TypeAttributes GetAttributeFlagsImpl() - { - throw new NotImplementedException(); - } - - protected override ConstructorInfo GetConstructorImpl( - BindingFlags bindingAttr, - Binder binder, - CallingConventions callConvention, - Type[] types, ParameterModifier[] modifiers) - { - throw new NotImplementedException(); - } - - public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override Type GetElementType() - { - throw new NotImplementedException(); - } - - public override EventInfo GetEvent(string name, BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override EventInfo[] GetEvents(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override FieldInfo GetField(string name, BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override FieldInfo[] GetFields(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override MemberInfo[] GetMembers(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - protected override MethodInfo GetMethodImpl( - string name, - BindingFlags bindingAttr, - Binder binder, - CallingConventions callConvention, - Type[] types, - ParameterModifier[] modifiers) - { - throw new NotImplementedException(); - } - - public override MethodInfo[] GetMethods(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override object InvokeMember( - string name, - BindingFlags invokeAttr, - Binder binder, - object target, - object[] args, - ParameterModifier[] modifiers, - CultureInfo culture, - string[] namedParameters) - { - throw new NotImplementedException(); - } - - public override Type UnderlyingSystemType { get; } - - protected override bool IsArrayImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsByRefImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsCOMObjectImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsPointerImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsPrimitiveImpl() - { - throw new NotImplementedException(); - } - - public override Assembly Assembly { get; } - public override string AssemblyQualifiedName { get; } - public override Type BaseType { get; } - public override string FullName { get; } - public override Guid GUID { get; } - - protected override PropertyInfo GetPropertyImpl( - string name, - BindingFlags bindingAttr, - Binder binder, - Type returnType, - Type[] types, - ParameterModifier[] modifiers) - { - throw new NotImplementedException(); - } - - protected override bool HasElementTypeImpl() - { - throw new NotImplementedException(); - } - - public override Type GetNestedType(string name, BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override Type[] GetNestedTypes(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override Type GetInterface(string name, bool ignoreCase) - { - throw new NotImplementedException(); - } - - public override Type[] GetInterfaces() - { - throw new NotImplementedException(); - } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/LazyRemoteTypeResolver.cs b/MTGOSDK/src/Core/Remoting/Internal/Reflection/LazyRemoteTypeResolver.cs deleted file mode 100644 index 73abf71b..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/LazyRemoteTypeResolver.cs +++ /dev/null @@ -1,40 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - - -namespace MTGOSDK.Core.Remoting.Internal.Reflection; - -public class LazyRemoteTypeResolver -{ - private Lazy _factory; - private string _beforeDumpingTypeName; - private string _beforeDumpingAssemblyName; - private Type _resolved; - - public string Assembly => _resolved?.Assembly?.FullName ?? _beforeDumpingAssemblyName; - public string TypeFullName => _resolved?.FullName ?? _beforeDumpingTypeName; - - public Type Value - { - get - { - _resolved ??= _factory.Value; - return _resolved; - } - } - - public LazyRemoteTypeResolver(Lazy factory, string assembly, string typeFullName) - { - _factory = factory; - _beforeDumpingAssemblyName = assembly; - _beforeDumpingTypeName = typeFullName; - } - - public LazyRemoteTypeResolver(Type resolved) - { - _resolved = resolved; - } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteConstructorInfo.cs b/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteConstructorInfo.cs deleted file mode 100644 index 0a40b943..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteConstructorInfo.cs +++ /dev/null @@ -1,94 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -using System.Globalization; -using System.Reflection; - - -namespace MTGOSDK.Core.Remoting.Internal.Reflection; - -public class RemoteConstructorInfo(Type declaringType, - ParameterInfo[] paramInfos) : ConstructorInfo -{ - public override MethodAttributes Attributes => throw new NotImplementedException(); - - public override RuntimeMethodHandle MethodHandle => throw new NotImplementedException(); - - public override Type DeclaringType { get; } = declaringType; - - public override string Name => ".ctor"; - - public override Type ReflectedType => throw new NotImplementedException(); - - private RemoteHandle App => (DeclaringType as RemoteType)?.App; - - public RemoteConstructorInfo(RemoteType declaringType, ConstructorInfo ci) : - this(declaringType, - ci.GetParameters().Select(pi => - new RemoteParameterInfo(pi)).Cast().ToArray()) - { } - - public override object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - public override MethodImplAttributes GetMethodImplementationFlags() - { - throw new NotImplementedException(); - } - - public override ParameterInfo[] GetParameters() => paramInfos; - - public override object Invoke( - BindingFlags invokeAttr, - Binder binder, - object[] parameters, - CultureInfo culture) - { - return RemoteFunctionsInvokeHelper - .Invoke( - App, - DeclaringType, - Name, - null, - new Type[0], - parameters); - } - - public override object Invoke( - object obj, - BindingFlags invokeAttr, - Binder binder, - object[] parameters, - CultureInfo culture) - { - // Empirically, invoking a ctor on an existing object should return null. - if (obj == null) - { - // Last chance - If this overload was used but no real object given lets - // redirect to normal Invoke (also happens with normal 'ConstructorInfo's) - return Invoke(invokeAttr, binder, parameters, culture); - } - return null; - } - - public override bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - public override string ToString() - { - string args = string.Join(", ", paramInfos.Select(pi => pi.ParameterType.FullName)); - return $"Void {this.Name}({args})"; - } -} diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteEnum.cs b/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteEnum.cs deleted file mode 100644 index 5bf4bf52..00000000 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteEnum.cs +++ /dev/null @@ -1,28 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - -namespace MTGOSDK.Core.Remoting.Internal.Reflection; - -public class RemoteEnum(RemoteType remoteType) -{ - public RemoteHandle App => remoteType?.App; - - public object GetValue(string valueName) - { - // NOTE: This is breaking the "RemoteX"/"DynamicX" paradigm because we are - // effectively returning a DRO here. - // - // Unlike RemoteObject which directly uses a remote token + TypeDump to - // read/write fields/props/methods, RemoteEnum was created after - // RemoteType was defined and it felt much easier to utilize it. - // - // RemoteType itself, as part of the reflection API, returns DROs. - RemoteFieldInfo verboseField = remoteType.GetField(valueName) as RemoteFieldInfo; - return verboseField.GetValue(null); - } - - public dynamic Dynamify() => new DynamicRemoteEnum(this); -} diff --git a/MTGOSDK/src/Core/Remoting/Interop/CallbacksListener.cs b/MTGOSDK/src/Core/Remoting/Interop/CallbacksListener.cs index 70c83f56..5a057e95 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/CallbacksListener.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/CallbacksListener.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.IO; diff --git a/MTGOSDK/src/Core/Remoting/Interop/DiverCommunicator.cs b/MTGOSDK/src/Core/Remoting/Interop/DiverCommunicator.cs index 32b4e87d..3a66b817 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/DiverCommunicator.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/DiverCommunicator.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Collections.Specialized; @@ -12,7 +12,7 @@ using System.Web; using Newtonsoft.Json; -using MTGOSDK.Core.Remoting.Interop.Exceptions; +using MTGOSDK.Core.Exceptions; using MTGOSDK.Core.Remoting.Interop.Interactions; using MTGOSDK.Core.Remoting.Interop.Interactions.Callbacks; using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; @@ -117,10 +117,10 @@ public HeapDump DumpHeap(string typeFilter = null, bool dumpHashcodes = true) return heapDump; } - public DomainsDump DumpDomains() + public DomainDump DumpDomain() { string body = SendRequest("domains", null); - DomainsDump? results = JsonConvert.DeserializeObject(body, _withErrors); + DomainDump results = JsonConvert.DeserializeObject(body, _withErrors)!; return results; } diff --git a/MTGOSDK/src/Core/Remoting/Interop/Exceptions/RemoteObjectMovedException.cs b/MTGOSDK/src/Core/Remoting/Interop/Exceptions/RemoteObjectMovedException.cs deleted file mode 100644 index 53d3a190..00000000 --- a/MTGOSDK/src/Core/Remoting/Interop/Exceptions/RemoteObjectMovedException.cs +++ /dev/null @@ -1,14 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - - -namespace MTGOSDK.Core.Remoting.Interop.Exceptions; - -internal class RemoteObjectMovedException(ulong testedAddress, - string msg) : Exception(msg) -{ - public ulong TestedAddress { get; private set; } = testedAddress; -} diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/CallbackInvocationRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/CallbackInvocationRequest.cs index fbb38e8d..94031c45 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/CallbackInvocationRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/CallbackInvocationRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/EventRegistrationResults.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/EventRegistrationResults.cs index 3c85c04c..7f404fb1 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/EventRegistrationResults.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/EventRegistrationResults.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/RegisteredEventHandlerInfo.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/RegisteredEventHandlerInfo.cs index b9b9cf24..17906cd7 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/RegisteredEventHandlerInfo.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Callbacks/RegisteredEventHandlerInfo.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Client/UnregisterClientResponse.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Client/UnregisterClientResponse.cs index 80c144fc..2fe303eb 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Client/UnregisterClientResponse.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Client/UnregisterClientResponse.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/DiverError.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/DiverError.cs index e6c73d1d..c74b9de6 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/DiverError.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/DiverError.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/DomainDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/DomainDump.cs new file mode 100644 index 00000000..9b0a21de --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/DomainDump.cs @@ -0,0 +1,23 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System; +using System.Collections.Generic; + + +namespace MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; + +// public readonly record struct DomainDump +// ( +// string Name, +// IList Modules +// ); + +public class DomainDump(string name, IList modules) +{ + public string Name { get; set; } = name; + public IList Modules { get; set; } = modules; +} diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/DomainsDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/DomainsDump.cs deleted file mode 100644 index 84577a4a..00000000 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/DomainsDump.cs +++ /dev/null @@ -1,19 +0,0 @@ -/** @file - Copyright (c) 2021, Xappy. - Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT -**/ - - -namespace MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; - -public class DomainsDump -{ - public struct AvailableDomain - { - public string Name { get; set; } - public List AvailableModules { get; set; } - } - public string Current { get; set; } - public List AvailableDomains { get; set; } -} diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/HeapDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/HeapDump.cs index 33eec01c..d7469482 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/HeapDump.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/HeapDump.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/MemberDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/MemberDump.cs index 1e594dea..d42a5739 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/MemberDump.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/MemberDump.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDump.cs index 6ce63dcc..ce49cb24 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDump.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDump.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDumpFactory.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDumpFactory.cs index d42ed494..e71ee0b8 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDumpFactory.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectDumpFactory.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System; @@ -9,7 +9,8 @@ using System.Linq; using System.Reflection; -using MTGOSDK.Core.Remoting.Interop.Utils; +using MTGOSDK.Core.Reflection.Extensions; +using MTGOSDK.Core.Remoting.Interop; namespace MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectType.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectType.cs index d667d06a..6b2563e7 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectType.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/ObjectType.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDump.cs index 7180e86b..4314a279 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDump.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDump.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Diagnostics; diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDumpRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDumpRequest.cs index 482044aa..d4c6db47 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDumpRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypeDumpRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypesDump.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypesDump.cs index b7c2d1f9..fad2e802 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypesDump.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Dumps/TypesDump.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationRequest.cs index 7622d71a..4cb04a55 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationResults.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationResults.cs index bd254200..fbd2f30b 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationResults.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/InvocationResults.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/CtorInvocationRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/CtorInvocationRequest.cs index ff17410d..0c9212ae 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/CtorInvocationRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/CtorInvocationRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldGetRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldGetRequest.cs index ed0d7f28..7d0aaf2c 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldGetRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldGetRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldSetRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldSetRequest.cs index 7e474d5d..9c43f68b 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldSetRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/FieldSetRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/IndexedItemAccessRequest.cs b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/IndexedItemAccessRequest.cs index fc483777..572ae9bc 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/IndexedItemAccessRequest.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/Interactions/Object/IndexedItemAccessRequest.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ diff --git a/MTGOSDK/src/Core/Remoting/Interop/ObjectOrRemoteAddress.cs b/MTGOSDK/src/Core/Remoting/Interop/ObjectOrRemoteAddress.cs index c02c60b2..725eb728 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/ObjectOrRemoteAddress.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/ObjectOrRemoteAddress.cs @@ -1,56 +1,53 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ -using MTGOSDK.Core.Remoting.Interop.Utils; +namespace MTGOSDK.Core.Remoting.Interop; -namespace MTGOSDK.Core.Remoting.Interop +/// +/// Represents either an encoded object (for primitive types like int, string, +/// primitive arrays...) or info of a remote object. +/// +public class ObjectOrRemoteAddress { /// - /// Represents either an encoded object (for primitive types like int, string, - /// primitive arrays...) or info of a remote object. + /// Whether or are set. /// - public class ObjectOrRemoteAddress - { - /// - /// Whether or are set. - /// - public bool IsRemoteAddress { get; set; } - public bool IsType { get; set; } - public string Type { get; set; } - public string Assembly { get; set; } - public ulong RemoteAddress { get; set; } - public string EncodedObject { get; set; } - public bool IsNull => IsRemoteAddress && RemoteAddress == 0; + public bool IsRemoteAddress { get; set; } + public bool IsType { get; set; } + public string Type { get; set; } + public string Assembly { get; set; } + public ulong RemoteAddress { get; set; } + public string EncodedObject { get; set; } + public bool IsNull => IsRemoteAddress && RemoteAddress == 0; - public static ObjectOrRemoteAddress FromObj(object o) => - new() { - EncodedObject = PrimitivesEncoder.Encode(o), - Type = o.GetType().FullName - }; + public static ObjectOrRemoteAddress FromObj(object o) => + new() { + EncodedObject = PrimitivesEncoder.Encode(o), + Type = o.GetType().FullName + }; - public static ObjectOrRemoteAddress FromToken(ulong addr, string type) => - new() { - IsRemoteAddress = true, - RemoteAddress = addr, - Type = type - }; + public static ObjectOrRemoteAddress FromToken(ulong addr, string type) => + new() { + IsRemoteAddress = true, + RemoteAddress = addr, + Type = type + }; - public static ObjectOrRemoteAddress Null => - new() { - IsRemoteAddress = true, - RemoteAddress = 0, - Type = typeof(object).FullName - }; + public static ObjectOrRemoteAddress Null => + new() { + IsRemoteAddress = true, + RemoteAddress = 0, + Type = typeof(object).FullName + }; - public static ObjectOrRemoteAddress FromType(Type type) => - new() { - Type = type.FullName, - Assembly = type.Assembly.GetName().Name, - IsType = true - }; - } + public static ObjectOrRemoteAddress FromType(Type type) => + new() { + Type = type.FullName, + Assembly = type.Assembly.GetName().Name, + IsType = true + }; } diff --git a/MTGOSDK/src/Core/Remoting/Interop/Utils/PrimitivesEncoder.cs b/MTGOSDK/src/Core/Remoting/Interop/PrimitivesEncoder.cs similarity index 94% rename from MTGOSDK/src/Core/Remoting/Interop/Utils/PrimitivesEncoder.cs rename to MTGOSDK/src/Core/Remoting/Interop/PrimitivesEncoder.cs index a4c4fb93..044d9a2e 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/Utils/PrimitivesEncoder.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/PrimitivesEncoder.cs @@ -1,11 +1,13 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ +using MTGOSDK.Core.Reflection.Extensions; -namespace MTGOSDK.Core.Remoting.Interop.Utils; + +namespace MTGOSDK.Core.Remoting.Interop; public static class PrimitivesEncoder { @@ -25,7 +27,7 @@ public static string Encode(object toEncode) return $"\"{toEncode}\""; } - if (t.IsPrimitiveEtc() || t.IsStringCoercible()) + if (t.IsPrimitiveEtc() || t.IsStringCoercible() || t.IsEnum) { // These types can just be ".Parse()"-ed back return toEncode.ToString(); @@ -109,6 +111,12 @@ public static object Decode(string toDecode, Type resultType) return parseMethod.Invoke(null, new object[] { toDecode }); } + // If the type is an enum, we can parse it directly from the string + if (resultType.IsEnum) + { + return Enum.Parse(resultType, toDecode); + } + if (resultType.IsArray) { Type elementType = resultType.GetElementType(); diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteFunctionsInvokeHelper.cs b/MTGOSDK/src/Core/Remoting/Interop/RemoteFunctionsInvokeHelper.cs similarity index 90% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteFunctionsInvokeHelper.cs rename to MTGOSDK/src/Core/Remoting/Interop/RemoteFunctionsInvokeHelper.cs index 0e95e138..484faf1c 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteFunctionsInvokeHelper.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/RemoteFunctionsInvokeHelper.cs @@ -1,20 +1,22 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ +using MTGOSDK.Core.Reflection.Extensions; using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Core.Remoting.Interop.Interactions; -using MTGOSDK.Core.Remoting.Interop.Utils; +using MTGOSDK.Core.Remoting.Reflection; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; +namespace MTGOSDK.Core.Remoting.Interop; /// /// In this context: "function" = Methods + Constructors. /// -internal static class RemoteFunctionsInvokeHelper +public static class RemoteFunctionsInvokeHelper { public static ObjectOrRemoteAddress CreateRemoteParameter(object parameter) { @@ -24,7 +26,8 @@ public static ObjectOrRemoteAddress CreateRemoteParameter(object parameter) } else if (parameter.GetType().IsPrimitiveEtc() || parameter.GetType().IsPrimitiveEtcArray() - || parameter.GetType().IsStringCoercible()) + || parameter.GetType().IsStringCoercible() + || parameter.GetType().IsEnum) { return ObjectOrRemoteAddress.FromObj(parameter); } @@ -37,7 +40,8 @@ public static ObjectOrRemoteAddress CreateRemoteParameter(object parameter) { RemoteObject originRemoteObject = dro.__ro; return ObjectOrRemoteAddress - .FromToken(originRemoteObject.RemoteToken, originRemoteObject.GetType().FullName); + .FromToken(originRemoteObject.RemoteToken, + originRemoteObject.GetType().FullName); } else if (parameter is Type t) { @@ -59,13 +63,15 @@ public static object Invoke( object obj, Type[] genericArgs, object[] parameters) - => Invoke( + { + return Invoke( app, declaringType, funcName, obj, genericArgs.Select(arg => arg.FullName).ToArray(), parameters); + } public static object Invoke( RemoteHandle app, diff --git a/MTGOSDK/src/Core/Remoting/Internal/RemoteObjectRef.cs b/MTGOSDK/src/Core/Remoting/Interop/RemoteObjectRef.cs similarity index 83% rename from MTGOSDK/src/Core/Remoting/Internal/RemoteObjectRef.cs rename to MTGOSDK/src/Core/Remoting/Interop/RemoteObjectRef.cs index 614bd2ed..aab243e5 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/RemoteObjectRef.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/RemoteObjectRef.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using MTGOSDK.Core.Remoting.Interop; @@ -9,7 +9,7 @@ using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; -namespace MTGOSDK.Core.Remoting.Internal; +namespace MTGOSDK.Core.Remoting.Interop; internal class RemoteObjectRef( ObjectDump remoteObjectInfo, @@ -24,11 +24,20 @@ internal class RemoteObjectRef( public TypeDump GetTypeDump() => typeInfo; + private void ThrowIfReleased() + { + if (_isReleased) + { + throw new ObjectDisposedException( + "Cannot use RemoteObjectRef object after `Release` have been called"); + } + } + /// - /// Gets the value of a remote field. Returned value might be a cached version unless is set to True. + /// Gets the value of a remote field. /// /// Name of field to get the value of - /// Whether the value should be read again for this invocation or a cache version is good enough + /// Whether to refresh or use a cached value public MemberDump GetFieldDump(string name, bool refresh = false) { ThrowIfReleased(); @@ -46,11 +55,12 @@ public MemberDump GetFieldDump(string name, bool refresh = false) // field has a value. Returning as-is for the user to parse return field; } + /// - /// Gets the value of a remote property. Returned value might be a cached version unless is set to True. + /// Gets the value of a remote property. /// /// Name of property to get the value of - /// Whether the value should be read again for this invocation or a cache version is good enough + /// Whether to refresh or use a cached value public MemberDump GetProperty(string name, bool refresh = false) { ThrowIfReleased(); @@ -66,18 +76,10 @@ public MemberDump GetProperty(string name, bool refresh = false) $"Property of the remote object could not be retrieved. Error: {property.RetrievalError}"); } - // property has a value. Returning as-is for the user to parse + // Property has a value. Returning as-is for the user to parse. return property; } - private void ThrowIfReleased() - { - if (_isReleased) - { - throw new ObjectDisposedException("Cannot use RemoteObjectRef object after `Release` have been called"); - } - } - public InvocationResults InvokeMethod( string methodName, string[] genericArgsFullTypeNames, diff --git a/MTGOSDK/src/Core/Remoting/Interop/ReverseCommunicator.cs b/MTGOSDK/src/Core/Remoting/Interop/ReverseCommunicator.cs index 1d5d9d2e..4966ca3a 100644 --- a/MTGOSDK/src/Core/Remoting/Interop/ReverseCommunicator.cs +++ b/MTGOSDK/src/Core/Remoting/Interop/ReverseCommunicator.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Net; diff --git a/MTGOSDK/src/Core/Remoting/LazyRemoteObject.cs b/MTGOSDK/src/Core/Remoting/Reflection/LazyRemoteObject.cs similarity index 90% rename from MTGOSDK/src/Core/Remoting/LazyRemoteObject.cs rename to MTGOSDK/src/Core/Remoting/Reflection/LazyRemoteObject.cs index 1a86144f..ffbb5dc6 100644 --- a/MTGOSDK/src/Core/Remoting/LazyRemoteObject.cs +++ b/MTGOSDK/src/Core/Remoting/Reflection/LazyRemoteObject.cs @@ -3,11 +3,10 @@ SPDX-License-Identifier: Apache-2.0 **/ -using MTGOSDK.Core.Remoting.Internal; -using MTGOSDK.Core.Remoting.Internal.Reflection; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting; +namespace MTGOSDK.Core.Remoting.Reflection; /// /// A wrapper for lazy initializing dynamic remote objects. diff --git a/MTGOSDK/src/Core/Remoting/Reflection/LazyRemoteTypeResolver.cs b/MTGOSDK/src/Core/Remoting/Reflection/LazyRemoteTypeResolver.cs new file mode 100644 index 00000000..1af3e4bc --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Reflection/LazyRemoteTypeResolver.cs @@ -0,0 +1,24 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Remoting.Reflection; + +public class LazyRemoteTypeResolver( + Lazy factory, + string assembly, + string typeFullName) +{ + public string Assembly => assembly; + public string TypeFullName => typeFullName; + public Type Value => factory.Value; + + public LazyRemoteTypeResolver(Type resolvedType) + : this(new Lazy(() => resolvedType), + resolvedType.Assembly.FullName, + resolvedType.FullName) + { } +} diff --git a/MTGOSDK/src/Core/Remoting/Reflection/RemoteConstructorInfo.cs b/MTGOSDK/src/Core/Remoting/Reflection/RemoteConstructorInfo.cs new file mode 100644 index 00000000..984af097 --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Reflection/RemoteConstructorInfo.cs @@ -0,0 +1,69 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Globalization; +using System.Reflection; + +using MTGOSDK.Core.Reflection.Types; +using MTGOSDK.Core.Remoting.Interop; +using MTGOSDK.Core.Remoting.Types; + + +namespace MTGOSDK.Core.Remoting.Reflection; + +public class RemoteConstructorInfo( + Type declaringType, + ParameterInfo[] paramInfos) : ConstructorInfoStub +{ + public override string Name => ".ctor"; + public override Type DeclaringType => declaringType; + + private RemoteHandle App => (declaringType as RemoteType)?.App; + + public RemoteConstructorInfo(RemoteType declaringType, ConstructorInfo ci) : + this(declaringType, + ci.GetParameters() + .Select(pi => new RemoteParameterInfo(pi)) + .Cast() + .ToArray()) + { } + + public override ParameterInfo[] GetParameters() => paramInfos; + + public override object Invoke( + BindingFlags invokeAttr, + Binder binder, + object[] parameters, + CultureInfo culture) + { + return RemoteFunctionsInvokeHelper + .Invoke(App, DeclaringType, Name, null, new Type[0], parameters); + } + + public override object Invoke( + object obj, + BindingFlags invokeAttr, + Binder binder, + object[] parameters, + CultureInfo culture) + { + // Empirically, invoking a ctor on an existing object should return null. + if (obj == null) + { + // Last chance - If this overload was used but no real object given lets + // redirect to normal Invoke (also happens with normal 'ConstructorInfo's) + return Invoke(invokeAttr, binder, parameters, culture); + } + + return null; + } + + public override string ToString() + { + string args = string.Join(", ", paramInfos.Select(pi => pi.ParameterType.FullName)); + return $"Void {this.Name}({args})"; + } +} diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteEventInfo.cs b/MTGOSDK/src/Core/Remoting/Reflection/RemoteEventInfo.cs similarity index 89% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteEventInfo.cs rename to MTGOSDK/src/Core/Remoting/Reflection/RemoteEventInfo.cs index 5d5e5bdc..59c86182 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteEventInfo.cs +++ b/MTGOSDK/src/Core/Remoting/Reflection/RemoteEventInfo.cs @@ -1,13 +1,15 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Reflection; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; + +namespace MTGOSDK.Core.Remoting.Reflection; public class RemoteEventInfo( RemoteType declaringType, @@ -17,9 +19,8 @@ public class RemoteEventInfo( public override EventAttributes Attributes => throw new NotImplementedException(); - public override Type DeclaringType { get; } = declaringType; - - public override string Name { get; } = name; + public override Type DeclaringType => declaringType; + public override string Name => name; public override Type ReflectedType => throw new NotImplementedException(); diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteFieldInfo.cs b/MTGOSDK/src/Core/Remoting/Reflection/RemoteFieldInfo.cs similarity index 86% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteFieldInfo.cs rename to MTGOSDK/src/Core/Remoting/Reflection/RemoteFieldInfo.cs index 3188220d..5fdd9cd6 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteFieldInfo.cs +++ b/MTGOSDK/src/Core/Remoting/Reflection/RemoteFieldInfo.cs @@ -1,22 +1,23 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Globalization; using System.Reflection; +using MTGOSDK.Core.Reflection.Types; using MTGOSDK.Core.Remoting.Interop; -using MTGOSDK.Core.Remoting.Interop.Utils; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; +namespace MTGOSDK.Core.Remoting.Reflection; public class RemoteFieldInfo( Type declaringType, Lazy fieldType, - string name) : FieldInfo + string name) : FieldInfoStub { private RemoteHandle App => (DeclaringType as RemoteType)?.App; @@ -32,22 +33,6 @@ public RemoteFieldInfo(RemoteType declaringType, FieldInfo fi) : this(declaringType, new Lazy(()=> fi.FieldType), fi.Name) { } - public override object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - public override bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - - public override Type ReflectedType { get; } public override object GetValue(object obj) { ObjectOrRemoteAddress oora = null; @@ -154,8 +139,5 @@ public override void SetValue( $"{nameof(RemoteFieldInfo)}.{nameof(SetValue)} only supports {nameof(RemoteObject)} or {nameof(DynamicRemoteObject)} targets."); } - public override FieldAttributes Attributes { get; } - public override RuntimeFieldHandle FieldHandle { get; } - public override string ToString() => $"{FieldType.FullName} {Name}"; } diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteMethodInfo.cs b/MTGOSDK/src/Core/Remoting/Reflection/RemoteMethodInfo.cs similarity index 65% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteMethodInfo.cs rename to MTGOSDK/src/Core/Remoting/Reflection/RemoteMethodInfo.cs index 8240e30a..47a1d216 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteMethodInfo.cs +++ b/MTGOSDK/src/Core/Remoting/Reflection/RemoteMethodInfo.cs @@ -1,50 +1,42 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Globalization; using System.Reflection; +using MTGOSDK.Core.Reflection.Types; +using MTGOSDK.Core.Remoting.Interop; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; + +namespace MTGOSDK.Core.Remoting.Reflection; public class RemoteMethodInfo( Type declaringType, LazyRemoteTypeResolver returnType, string name, Type[] genericArgs, - ParameterInfo[] paramInfos) : MethodInfo + ParameterInfo[] paramInfos) : MethodInfoStub { - public override ICustomAttributeProvider ReturnTypeCustomAttributes => - throw new NotImplementedException(); - public override string Name { get; } = name; public override Type DeclaringType { get; } = declaringType; public override Type ReturnType => returnType.Value; - public override Type ReflectedType => - throw new NotImplementedException(); - - public override RuntimeMethodHandle MethodHandle => - throw new NotImplementedException(); - - public override MethodAttributes Attributes => - throw new NotImplementedException(); - public override bool IsGenericMethod => AssignedGenericArgs.Length > 0; public override bool IsGenericMethodDefinition => AssignedGenericArgs.Length > 0 && - AssignedGenericArgs.All(t => t is DummyGenericType); + AssignedGenericArgs.All(t => t is TypeStub); public override bool ContainsGenericParameters => AssignedGenericArgs.Length > 0 && - AssignedGenericArgs.All(t => t is DummyGenericType); + AssignedGenericArgs.All(t => t is TypeStub); public override Type[] GetGenericArguments() => AssignedGenericArgs; @@ -77,23 +69,8 @@ public override MethodInfo MakeGenericMethod(params Type[] typeArguments) return new RemoteMethodInfo(DeclaringType, ReturnType, Name, typeArguments, paramInfos); } - public override object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public override bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - public override ParameterInfo[] GetParameters() => paramInfos; - public override MethodImplAttributes GetMethodImplementationFlags() - { - throw new NotImplementedException(); - } - public override object Invoke( object obj, BindingFlags invokeAttr, @@ -104,17 +81,6 @@ public override object Invoke( return RemoteFunctionsInvokeHelper .Invoke(this.App, DeclaringType, Name, obj, AssignedGenericArgs, parameters); } - - public override MethodInfo GetBaseDefinition() - { - throw new NotImplementedException(); - } - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - public override string ToString() { try diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteParameterInfo.cs b/MTGOSDK/src/Core/Remoting/Reflection/RemoteParameterInfo.cs similarity index 60% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteParameterInfo.cs rename to MTGOSDK/src/Core/Remoting/Reflection/RemoteParameterInfo.cs index 6044c674..c1e0bac4 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteParameterInfo.cs +++ b/MTGOSDK/src/Core/Remoting/Reflection/RemoteParameterInfo.cs @@ -1,20 +1,27 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Reflection; +using MTGOSDK.Core.Reflection.Types; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; + +namespace MTGOSDK.Core.Remoting.Reflection; /// -/// A parameter of a remote method. The parameter's type itself might be a remote type (but can also be local) +/// A parameter of a remote method. /// +/// +/// The parameter's type itself might also be a remote type but it can also +/// represent a local type. +/// public class RemoteParameterInfo( string name, - LazyRemoteTypeResolver paramType) : ParameterInfo + LazyRemoteTypeResolver paramType) : ParameterInfoStub { public override string Name { get; } = name; diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemotePropertyInfo.cs b/MTGOSDK/src/Core/Remoting/Reflection/RemotePropertyInfo.cs similarity index 66% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemotePropertyInfo.cs rename to MTGOSDK/src/Core/Remoting/Reflection/RemotePropertyInfo.cs index 37b78fd4..8c8c7b14 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemotePropertyInfo.cs +++ b/MTGOSDK/src/Core/Remoting/Reflection/RemotePropertyInfo.cs @@ -1,32 +1,26 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Globalization; using System.Reflection; +using MTGOSDK.Core.Reflection.Types; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; -public class RemotePropertyInfo(Type declaringType, Lazy propType, string name) : PropertyInfo -{ - private RemoteHandle App => (DeclaringType as RemoteType)?.App; - public override PropertyAttributes Attributes => - throw new NotImplementedException(); - - public override bool CanRead => GetMethod != null; - public override bool CanWrite => SetMethod != null; - - public override Type PropertyType => propType.Value; - - public override Type DeclaringType { get; } = declaringType; +namespace MTGOSDK.Core.Remoting.Reflection; +public class RemotePropertyInfo( + Type declaringType, + Lazy propType, + string name) : PropertyInfoStub +{ public override string Name { get; } = name; - - public override Type ReflectedType => - throw new NotImplementedException(); + public override Type DeclaringType { get; } = declaringType; + public override Type PropertyType => propType.Value; public RemoteMethodInfo RemoteGetMethod { get; set; } public RemoteMethodInfo RemoteSetMethod { get; set; } @@ -34,37 +28,20 @@ public class RemotePropertyInfo(Type declaringType, Lazy propType, string public override MethodInfo GetMethod => RemoteGetMethod; public override MethodInfo SetMethod => RemoteSetMethod; + public override bool CanRead => GetMethod != null; + public override bool CanWrite => SetMethod != null; + public RemotePropertyInfo(Type declaringType, Type propType, string name) : this(declaringType, new Lazy(() => propType), name) - {} + { } public RemotePropertyInfo(RemoteType declaringType, PropertyInfo pi) : this(declaringType, new Lazy(() => pi.PropertyType), pi.Name) - {} - - public override MethodInfo[] GetAccessors(bool nonPublic) - { - throw new NotImplementedException(); - } - - public override object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } + { } public override MethodInfo GetGetMethod(bool nonPublic) => this.GetMethod; public override MethodInfo GetSetMethod(bool nonPublic) => this.SetMethod; - public override ParameterInfo[] GetIndexParameters() - { - throw new NotImplementedException(); - } - public override object GetValue( object obj, BindingFlags invokeAttr, @@ -83,11 +60,6 @@ public override object GetValue( } } - public override bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } - public override void SetValue( object obj, object value, diff --git a/MTGOSDK/src/Core/Remoting/RemoteActivator.cs b/MTGOSDK/src/Core/Remoting/RemoteActivator.cs index 825622cd..8f7101a0 100644 --- a/MTGOSDK/src/Core/Remoting/RemoteActivator.cs +++ b/MTGOSDK/src/Core/Remoting/RemoteActivator.cs @@ -1,12 +1,12 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Core.Remoting.Interop.Interactions; -using MTGOSDK.Core.Remoting.Internal.Reflection; +using MTGOSDK.Core.Remoting.Types; namespace MTGOSDK.Core.Remoting; @@ -35,16 +35,17 @@ public RemoteObject CreateInstance(string assembly, if (val.GetType().IsEnum) { var enumClass = app.GetRemoteEnum(val.GetType().FullName); - // TODO: This will break on the first enum value which represents 2 or more flags + // TODO: This breaks on the first enum value which has 2 or more flags. object enumVal = enumClass.GetValue(val.ToString()); - // NOTE: Object stays in place in the remote app as long as we have it's reference - // in the paramsNoEnums array (so until end of this method) + // NOTE: Object stays in place in the remote app as long as we have it's + // reference in the paramsNoEnums array (so until end of this method) paramsNoEnums[i] = enumVal; } } - ObjectOrRemoteAddress[] remoteParams = paramsNoEnums.Select( - RemoteFunctionsInvokeHelper.CreateRemoteParameter).ToArray(); + ObjectOrRemoteAddress[] remoteParams = paramsNoEnums + .Select(RemoteFunctionsInvokeHelper.CreateRemoteParameter) + .ToArray(); // Create object + pin InvocationResults invoRes = communicator diff --git a/MTGOSDK/src/Core/Remoting/RemoteClient.cs b/MTGOSDK/src/Core/Remoting/RemoteClient.cs index 7cd5e54c..fc656b37 100644 --- a/MTGOSDK/src/Core/Remoting/RemoteClient.cs +++ b/MTGOSDK/src/Core/Remoting/RemoteClient.cs @@ -10,6 +10,8 @@ using MTGOSDK.Core.Exceptions; using MTGOSDK.Core.Logging; using MTGOSDK.Core.Reflection; +using MTGOSDK.Core.Remoting.Types; +using MTGOSDK.Core.Remoting.Structs; using MTGOSDK.Resources; using MTGOSDK.Win32.API; @@ -118,7 +120,7 @@ private static Process MTGOProcess() => /// attempt to install or update the client before starting it. /// /// True if the MTGO client process was started. - /// + /// /// Thrown when the MTGO installation has failed. /// /// @@ -177,7 +179,7 @@ public static async Task StartProcess() (await WaitUntil(() => IsUpdating, delay: 250, retries: 20 )) && !(await WaitUntil(() => HasStarted, delay: 5000, retries: 60 ))) { - throw new SetupFailedException("The MTGO installation has failed."); + throw new SetupFailureException("The MTGO installation has failed."); } // @@ -186,7 +188,7 @@ public static async Task StartProcess() // if (!(await WaitUntil(() => HasStarted)) && (IsStarting || IsUpdating)) { - throw new SetupFailedException( + throw new SetupFailureException( "The MTGO installation stalled and did not finish."); } else if (!HasStarted) diff --git a/MTGOSDK/src/Core/Remoting/RemoteHandle.cs b/MTGOSDK/src/Core/Remoting/RemoteHandle.cs index ff836ec0..98f17d1d 100644 --- a/MTGOSDK/src/Core/Remoting/RemoteHandle.cs +++ b/MTGOSDK/src/Core/Remoting/RemoteHandle.cs @@ -1,17 +1,18 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Diagnostics; using System.IO; -using MTGOSDK.Core.Remoting.Internal; -using MTGOSDK.Core.Remoting.Internal.Reflection; +using MTGOSDK.Core.Reflection; using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; -using MTGOSDK.Core.Remoting.Interop.Utils; +using MTGOSDK.Core.Remoting.Reflection; +using MTGOSDK.Core.Remoting.Types; +using MTGOSDK.Core.Remoting.Structs; using MTGOSDK.Resources; @@ -107,7 +108,7 @@ public RemoteObject GetRemoteObject( } private Process _procWithDiver; - private DomainsDump _domains; + private DomainDump _currentDomain; private readonly RemoteObjectsCollection _remoteObjects; public Process Process => _procWithDiver; @@ -121,6 +122,8 @@ internal RemoteHandle(Process procWithDiver, DiverCommunicator communicator) { _procWithDiver = procWithDiver; _communicator = communicator; + + _currentDomain = communicator.DumpDomain(); _remoteObjects = new RemoteObjectsCollection(this); Activator = new RemoteActivator(communicator, this); } @@ -143,7 +146,7 @@ public static RemoteHandle Connect(Process target, ushort diverPort) { // Use discovery to check for existing diver string diverAddr = "127.0.0.1"; - switch(DiverDiscovery.QueryStatus(target, diverAddr, diverPort)) + switch(Bootstrapper.QueryStatus(target, diverAddr, diverPort)) { case DiverState.NoDiver: // No diver, we need to inject one @@ -180,34 +183,30 @@ public static RemoteHandle Connect(Process target, ushort diverPort) public IEnumerable QueryTypes(string typeFullName) { - _domains ??= Communicator.DumpDomains(); - foreach (DomainsDump.AvailableDomain domain in _domains.AvailableDomains) + foreach (string assembly in _currentDomain.Modules) { - foreach (string assembly in domain.AvailableModules) + List typeIdentifiers; + // try + // { + typeIdentifiers = Communicator.DumpTypes(assembly).Types; + // } + // catch + // { + // // TODO: + // Debug.WriteLine($"[{nameof(RemoteHandle)}][{nameof(QueryTypes)}] Exception thrown when Dumping/Iterating assembly: {assembly}"); + // continue; + // } + foreach (TypesDump.TypeIdentifiers type in typeIdentifiers) { - List typeIdentifiers; - try - { - typeIdentifiers = Communicator.DumpTypes(assembly).Types; - } - catch - { - // TODO: - Debug.WriteLine($"[{nameof(RemoteHandle)}][{nameof(QueryTypes)}] Exception thrown when Dumping/Iterating assembly: {assembly}"); - continue; - } - foreach (TypesDump.TypeIdentifiers type in typeIdentifiers) - { - // TODO: Filtering should probably be done in the Diver's side - if (type.TypeName == typeFullName) - yield return new CandidateType(type.TypeName, assembly); - } - + // TODO: Filtering should probably be done in the Diver's side + if (type.TypeName == typeFullName) + yield return new CandidateType(type.TypeName, assembly); } } } - public IEnumerable QueryInstances(Type typeFilter, bool dumpHashcodes = true) => QueryInstances(typeFilter.FullName, dumpHashcodes); + public IEnumerable QueryInstances(Type typeFilter, bool dumpHashcodes = true) => + QueryInstances(typeFilter.FullName, dumpHashcodes); /// /// Gets all object candidates for a specific filter @@ -237,7 +236,7 @@ public IEnumerable QueryInstances(string typeFullNameFilter, bo public Type GetRemoteType(string typeFullName, string assembly = null) { // Easy case: Trying to resolve from cache or from local assemblies - var resolver = TypesResolver.Instance; + var resolver = TypeResolver.Instance; Type res = resolver.Resolve(assembly, typeFullName); if (res != null) { @@ -250,7 +249,7 @@ public Type GetRemoteType(string typeFullName, string assembly = null) { res = new RemoteType(this, res); // TODO: Registering here in the cache is a hack but we couldn't - // register within "TypesResolver.Resolve" because we don't have the + // register within "TypeResolver.Resolve" because we don't have the // RemoteHandle to associate the fake remote type with. // Maybe this should move somewhere else... resolver.RegisterType(res); @@ -308,6 +307,6 @@ public void Dispose() _procWithDiver = null; // Clear global type cache - TypesResolver.Instance._cache.Clear(); + TypeResolver.Instance.ClearCache(); } } diff --git a/MTGOSDK/src/Core/Remoting/Structs/CandidateObject.cs b/MTGOSDK/src/Core/Remoting/Structs/CandidateObject.cs new file mode 100644 index 00000000..6d0a8409 --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Structs/CandidateObject.cs @@ -0,0 +1,21 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Remoting.Structs; + +/// +/// A candidate for a remote object. +/// +/// +/// Holding this item does not mean having a meaningful hold of the remote object. +/// To gain one use +/// +public readonly record struct CandidateObject( + ulong Address, + string TypeFullName, + int HashCode +); diff --git a/MTGOSDK/src/Core/Remoting/Structs/CandidateType.cs b/MTGOSDK/src/Core/Remoting/Structs/CandidateType.cs new file mode 100644 index 00000000..60ce56fc --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Structs/CandidateType.cs @@ -0,0 +1,13 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + + +namespace MTGOSDK.Core.Remoting.Structs; + +public readonly record struct CandidateType( + string TypeFullName, + string Assembly +); diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/DynamicRemoteEnum.cs b/MTGOSDK/src/Core/Remoting/Types/DynamicRemoteEnum.cs similarity index 81% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/DynamicRemoteEnum.cs rename to MTGOSDK/src/Core/Remoting/Types/DynamicRemoteEnum.cs index f56a3990..c1398817 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/DynamicRemoteEnum.cs +++ b/MTGOSDK/src/Core/Remoting/Types/DynamicRemoteEnum.cs @@ -1,13 +1,13 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Dynamic; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; +namespace MTGOSDK.Core.Remoting.Types; public class DynamicRemoteEnum(RemoteEnum remoteEnum) : DynamicObject { diff --git a/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteEnumerator.cs b/MTGOSDK/src/Core/Remoting/Types/DynamicRemoteEnumerator.cs similarity index 87% rename from MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteEnumerator.cs rename to MTGOSDK/src/Core/Remoting/Types/DynamicRemoteEnumerator.cs index e22db88e..6908818d 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteEnumerator.cs +++ b/MTGOSDK/src/Core/Remoting/Types/DynamicRemoteEnumerator.cs @@ -1,13 +1,13 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Collections; -namespace MTGOSDK.Core.Remoting.Internal; +namespace MTGOSDK.Core.Remoting.Types; public class DynamicRemoteEnumerator(dynamic remoteEnumerator) : IEnumerator { diff --git a/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteObject.cs b/MTGOSDK/src/Core/Remoting/Types/DynamicRemoteObject.cs similarity index 98% rename from MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteObject.cs rename to MTGOSDK/src/Core/Remoting/Types/DynamicRemoteObject.cs index 768ad289..892d2888 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/DynamicRemoteObject.cs +++ b/MTGOSDK/src/Core/Remoting/Types/DynamicRemoteObject.cs @@ -1,7 +1,7 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Collections; @@ -13,14 +13,12 @@ using Microsoft.CSharp.RuntimeBinder; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; -using MTGOSDK.Core.Remoting.Internal.ProxiedReflection; -using MTGOSDK.Core.Remoting.Internal.Reflection; -using MTGOSDK.Core.Remoting.Internal.Utils; +using MTGOSDK.Core.Reflection.Extensions; using MTGOSDK.Core.Remoting.Interop; -using MTGOSDK.Core.Remoting.Interop.Utils; +using MTGOSDK.Core.Remoting.Reflection; -namespace MTGOSDK.Core.Remoting.Internal; +namespace MTGOSDK.Core.Remoting.Types; /// /// A proxy of a remote object. @@ -35,14 +33,14 @@ public class DynamicRemoteObject : DynamicObject, IEnumerable public class DynamicRemoteMethod : DynamicObject { string _name; - ProxiedMethodGroup _methods; + List _methods; DynamicRemoteObject _parent; Type[] _genericArguments; public DynamicRemoteMethod( string name, DynamicRemoteObject parent, - ProxiedMethodGroup methods, + List methods, Type[] genericArguments = null) { genericArguments ??= Array.Empty(); @@ -374,7 +372,7 @@ private DynamicRemoteMethod GetMethodProxy(string name) throw new Exception($"A method overload for \"{name}\" wasn't a MethodInfo"); } - ProxiedMethodGroup methodGroup = new ProxiedMethodGroup(); + List methodGroup = new(); methodGroup.AddRange(methods.Cast()); try { diff --git a/MTGOSDK/src/Core/Remoting/Types/RemoteAssembly.cs b/MTGOSDK/src/Core/Remoting/Types/RemoteAssembly.cs new file mode 100644 index 00000000..1f55ebee --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Types/RemoteAssembly.cs @@ -0,0 +1,26 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using System.Globalization; +using System.Reflection; + +using MTGOSDK.Core.Reflection.Types; + + +namespace MTGOSDK.Core.Remoting.Types; + +public class RemoteAssembly(string assemblyName) : Assembly +{ + private AssemblyName name = new(assemblyName); + + public override string FullName => + throw new Exception( + $"You tried to get the 'FullName' property on a {nameof(RemoteAssembly)}." + + $"Currently, this is forbidden to reduce confusion between 'full name' and 'short name'." + + $"You should call 'GetName().Name' instead."); + + public override AssemblyName GetName() => name; +} diff --git a/MTGOSDK/src/Core/Remoting/Types/RemoteEnum.cs b/MTGOSDK/src/Core/Remoting/Types/RemoteEnum.cs new file mode 100644 index 00000000..9315f151 --- /dev/null +++ b/MTGOSDK/src/Core/Remoting/Types/RemoteEnum.cs @@ -0,0 +1,23 @@ +/** @file + Copyright (c) 2021, Xappy. + Copyright (c) 2024, Cory Bennett. All rights reserved. + SPDX-License-Identifier: Apache-2.0 +**/ + +using MTGOSDK.Core.Remoting.Reflection; + + +namespace MTGOSDK.Core.Remoting.Types; + +public class RemoteEnum(RemoteType remoteType) +{ + public RemoteHandle App => remoteType?.App; + + public object GetValue(string valueName) + { + RemoteFieldInfo verboseField = remoteType.GetField(valueName) as RemoteFieldInfo; + return verboseField.GetValue(null); + } + + public dynamic Dynamify() => new DynamicRemoteEnum(this); +} diff --git a/MTGOSDK/src/Core/Remoting/RemoteObject.cs b/MTGOSDK/src/Core/Remoting/Types/RemoteObject.cs similarity index 91% rename from MTGOSDK/src/Core/Remoting/RemoteObject.cs rename to MTGOSDK/src/Core/Remoting/Types/RemoteObject.cs index 471664ac..6ceea0af 100644 --- a/MTGOSDK/src/Core/Remoting/RemoteObject.cs +++ b/MTGOSDK/src/Core/Remoting/Types/RemoteObject.cs @@ -1,16 +1,15 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ -using MTGOSDK.Core.Remoting.Internal; using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Core.Remoting.Interop.Interactions; using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; -namespace MTGOSDK.Core.Remoting; +namespace MTGOSDK.Core.Remoting.Types; public class RemoteObject { @@ -58,14 +57,7 @@ public ObjectOrRemoteAddress SetField(string fieldName, ObjectOrRemoteAddress ne return (true, invokeRes.ReturnedObjectOrAddress); } - public dynamic Dynamify() - { - // Adding fields - TypeDump typeDump = _ref.GetTypeDump(); - - var factory = new DynamicRemoteObjectFactory(); - return factory.Create(_app, this, typeDump); - } + public dynamic Dynamify() => new DynamicRemoteObject(_app, this); ~RemoteObject() { diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteType.cs b/MTGOSDK/src/Core/Remoting/Types/RemoteType.cs similarity index 51% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteType.cs rename to MTGOSDK/src/Core/Remoting/Types/RemoteType.cs index b65a1172..fb51f3c5 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteType.cs +++ b/MTGOSDK/src/Core/Remoting/Types/RemoteType.cs @@ -1,29 +1,19 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Globalization; using System.Reflection; +using MTGOSDK.Core.Reflection.Types; +using MTGOSDK.Core.Remoting.Reflection; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; -internal class RemoteAssemblyDummy(string assemblyName) : Assembly -{ - private AssemblyName name = new(assemblyName); - - public override string FullName => - throw new Exception( - $"You tried to get the 'FullName' property on a {nameof(RemoteAssemblyDummy)}." + - $"Currently, this is forbidden to reduce confusion between 'full name' and 'short name'." + - $"You should call 'GetName().Name' instead."); - - public override AssemblyName GetName() => name; -} +namespace MTGOSDK.Core.Remoting.Types; -public class RemoteType : Type +public class RemoteType : TypeStub { private readonly List _ctors = new List(); private readonly List _methods = new List(); @@ -33,7 +23,7 @@ public class RemoteType : Type private readonly bool _isArray; private readonly bool _isGenericParameter; - public RemoteHandle App { get; set; } + public RemoteHandle App; public override bool IsGenericParameter => _isGenericParameter; @@ -41,7 +31,11 @@ public class RemoteType : Type public override Type BaseType => _parent?.Value; public RemoteType(RemoteHandle app, Type localType) - : this(app, localType.FullName, localType.Assembly.GetName().Name, localType.IsArray, localType.IsGenericParameter) + : this(app, + localType.FullName, + localType.Assembly.GetName().Name, + localType.IsArray, + localType.IsGenericParameter) { if (localType is RemoteType) { @@ -49,13 +43,18 @@ public RemoteType(RemoteHandle app, Type localType) } // TODO: This ctor is experimentatl because it makes a LOT of assumptions. - // Most notably the RemoteXXXInfo objects freely use mi's,ci's,pi's (etc) "ReturnType","FieldType","PropertyType" + // Most notably the RemoteXXXInfo objects freely use mi's,ci's,pi's (etc) + // "ReturnType","FieldType","PropertyType" // not checking if they are actually RemoteTypes themselves... foreach (MethodInfo mi in localType.GetMethods()) + { AddMethod(new RemoteMethodInfo(this, mi)); + } foreach (ConstructorInfo ci in localType.GetConstructors()) + { AddConstructor(new RemoteConstructorInfo(this, ci)); + } foreach (PropertyInfo pi in localType.GetProperties()) { RemotePropertyInfo remotePropInfo = new RemotePropertyInfo(this, pi); @@ -64,9 +63,13 @@ public RemoteType(RemoteHandle app, Type localType) AddProperty(remotePropInfo); } foreach (FieldInfo fi in localType.GetFields()) + { AddField(new RemoteFieldInfo(this, fi)); + } foreach (EventInfo ei in localType.GetEvents()) + { AddEvent(new RemoteEventInfo(this, ei)); + } } public RemoteType( @@ -75,98 +78,52 @@ public RemoteType( string assemblyName, bool isArray, bool isGenericParameter = false) + : base(name: GetNameFromFullName(fullName), + assembly: new RemoteAssembly(assemblyName), + fullName: fullName) { App = app; - FullName = fullName; _isGenericParameter = isGenericParameter; _isArray = isArray; - Assembly = new RemoteAssemblyDummy(assemblyName); + } - // Derieving name from full name - Name = fullName.Substring(fullName.LastIndexOf('.') + 1); + private static string GetNameFromFullName(string fullName) + { + // Deriving name from full name + string name = fullName.Substring(fullName.LastIndexOf('.') + 1); if (fullName.Contains("`")) { // Generic. Need to cut differently string outterTypeFullName = fullName.Substring(0, fullName.IndexOf('`')); - Name = outterTypeFullName.Substring(outterTypeFullName.LastIndexOf('.') + 1); + name = outterTypeFullName.Substring(outterTypeFullName.LastIndexOf('.') + 1); } + + return name; } - public void AddConstructor(RemoteConstructorInfo rci) - { + public void AddConstructor(RemoteConstructorInfo rci) => _ctors.Add(rci); - } - public void AddMethod(RemoteMethodInfo rmi) - { + public void AddMethod(RemoteMethodInfo rmi) => _methods.Add(rmi); - } - public void AddField(RemoteFieldInfo fieldInfo) - { + public void AddField(RemoteFieldInfo fieldInfo) => _fields.Add(fieldInfo); - } - public void AddProperty(RemotePropertyInfo fieldInfo) - { - _properties.Add(fieldInfo); - } - public void AddEvent(RemoteEventInfo eventInfo) - { - _events.Add(eventInfo); - } - public override object[] GetCustomAttributes(bool inherit) - { - throw new NotImplementedException(); - } + public void AddProperty(RemotePropertyInfo fieldInfo) => + _properties.Add(fieldInfo); - public override bool IsDefined(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } + public void AddEvent(RemoteEventInfo eventInfo) => + _events.Add(eventInfo); public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => _ctors.Cast().ToArray(); - public override Type GetInterface(string name, bool ignoreCase) - { - throw new NotImplementedException(); - } - - public override Type[] GetInterfaces() - { - throw new NotImplementedException(); - } - - public override EventInfo GetEvent(string name, BindingFlags bindingAttr) - { - return GetEvents().Single(ei => ei.Name == name); - } - - public override EventInfo[] GetEvents(BindingFlags bindingAttr) - { - return _events.ToArray(); - } - - public override Type[] GetNestedTypes(BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override Type GetNestedType(string name, BindingFlags bindingAttr) - { - throw new NotImplementedException(); - } - - public override Type GetElementType() - { - throw new NotImplementedException(); - } + public override EventInfo GetEvent(string name, BindingFlags bindingAttr) => + GetEvents().Single(ei => ei.Name == name); - protected override bool HasElementTypeImpl() - { - throw new NotImplementedException(); - } + public override EventInfo[] GetEvents(BindingFlags bindingAttr) => + _events.ToArray(); protected override PropertyInfo GetPropertyImpl( string name, @@ -179,10 +136,8 @@ protected override PropertyInfo GetPropertyImpl( return GetProperties().Single(prop => prop.Name == name); } - public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) - { - return _properties.ToArray(); - } + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => + _properties.ToArray(); protected override MethodInfo GetMethodImpl( string name, @@ -216,120 +171,45 @@ bool overloadsComparer(MethodInfo method) return methodGroup.Single(overloadsComparer); } - public override MethodInfo[] GetMethods(BindingFlags bindingAttr) - { - return _methods.ToArray(); - } + public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => + _methods.ToArray(); - public override FieldInfo GetField(string name, BindingFlags bindingAttr) - { - return GetFields().Single(field => field.Name == name); - } + public override FieldInfo GetField(string name, BindingFlags bindingAttr) => + GetFields().Single(field => field.Name == name); - public override FieldInfo[] GetFields(BindingFlags bindingAttr) - { - return _fields.ToArray(); - } + public override FieldInfo[] GetFields(BindingFlags bindingAttr) => + _fields.ToArray(); - private IEnumerable GetMembersInner(BindingFlags bf) + private IEnumerable GetMembersInner(BindingFlags flags) { - foreach (var ctor in GetConstructors(bf)) + foreach (var ctor in GetConstructors(flags)) { yield return ctor; } - foreach (var field in GetFields(bf)) + foreach (var field in GetFields(flags)) { yield return field; } - foreach (var prop in GetProperties(bf)) + foreach (var prop in GetProperties(flags)) { yield return prop; } - foreach (var eventt in GetEvents(bf)) + foreach (var @event in GetEvents(flags)) { - yield return eventt; + yield return @event; } - foreach (var method in GetMethods(bf)) + foreach (var method in GetMethods(flags)) { yield return method; } } - internal void SetParent(Lazy parent) - { - _parent = parent; - } + internal void SetParent(Lazy parent) => _parent = parent; public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => GetMembersInner(bindingAttr).ToArray(); - protected override TypeAttributes GetAttributeFlagsImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsArrayImpl() - { - return _isArray; - } - - protected override bool IsByRefImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsPointerImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsPrimitiveImpl() - { - throw new NotImplementedException(); - } - - protected override bool IsCOMObjectImpl() - { - throw new NotImplementedException(); - } - - public override object InvokeMember( - string name, - BindingFlags invokeAttr, - Binder binder, - object target, - object[] args, - ParameterModifier[] modifiers, - CultureInfo culture, - string[] namedParameters) - { - throw new NotImplementedException(); - } - - public override Type UnderlyingSystemType { get; } - - protected override ConstructorInfo GetConstructorImpl( - BindingFlags bindingAttr, - Binder binder, - CallingConventions callConvention, - Type[] types, - ParameterModifier[] modifiers) - { - throw new NotImplementedException(); - } - - public override string Name { get; } - public override Guid GUID { get; } - public override Module Module { get; } - public override Assembly Assembly { get; } - public override string FullName { get; } - public override string Namespace { get; } - public override string AssemblyQualifiedName { get; } - - public override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - throw new NotImplementedException(); - } + protected override bool IsArrayImpl() => _isArray; public override string ToString() => FullName; } diff --git a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteTypesFactory.cs b/MTGOSDK/src/Core/Remoting/Types/RemoteTypesFactory.cs similarity index 97% rename from MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteTypesFactory.cs rename to MTGOSDK/src/Core/Remoting/Types/RemoteTypesFactory.cs index cec9362f..c8ee035f 100644 --- a/MTGOSDK/src/Core/Remoting/Internal/Reflection/RemoteTypesFactory.cs +++ b/MTGOSDK/src/Core/Remoting/Types/RemoteTypesFactory.cs @@ -1,19 +1,23 @@ /** @file Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. - SPDX-License-Identifier: Apache-2.0 and MIT + SPDX-License-Identifier: Apache-2.0 **/ using System.Diagnostics; using System.Reflection; +using MTGOSDK.Core.Reflection; +using MTGOSDK.Core.Reflection.Types; using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Core.Remoting.Interop.Interactions.Dumps; +using MTGOSDK.Core.Remoting.Reflection; +using MTGOSDK.Core.Remoting.Types; -namespace MTGOSDK.Core.Remoting.Internal.Reflection; +namespace MTGOSDK.Core.Remoting.Types; -public class RemoteTypesFactory(TypesResolver resolver, +public class RemoteTypesFactory(TypeResolver resolver, DiverCommunicator communicator) { /// @@ -61,7 +65,7 @@ public Type ResolveTypeWhileCreating( { paramType = new RemoteType(app, paramType); // TODO: Registring here in the cache is a hack but we couldn't - // register within "TypesResolver.Resolve" because we don't have the + // register within "TypeResolver.Resolve" because we don't have the // RemoteHandle to associate the fake remote type with. // // Maybe this should move somewhere else... @@ -343,7 +347,7 @@ private void AddGroupOfFunctions(RemoteHandle app, TypeDump typeDump, List new DummyGenericType(arg)).ToArray(); + Type[] genericArgs = func.GenericArgs.Select(arg => new TypeStub(arg)).ToArray(); // Regular method RemoteMethodInfo methodInfo = diff --git a/MTGOSDK/src/Core/Security/SecurityExtensions.cs b/MTGOSDK/src/Core/Security/SecurityExtensions.cs index cf8bf23e..05bf91a1 100644 --- a/MTGOSDK/src/Core/Security/SecurityExtensions.cs +++ b/MTGOSDK/src/Core/Security/SecurityExtensions.cs @@ -29,7 +29,7 @@ public static dynamic RemoteSecureString(this SecureString password) IntPtr passwordPtr = IntPtr.Zero; char @char; // Create a new SecureString object on the remote client. - dynamic secure_pwd = RemoteClient.CreateInstance(new Proxy()); + dynamic secure_pwd = RemoteClient.CreateInstance(new TypeProxy()); try { // Allocate a global handle for the password string in unmanaged memory. diff --git a/MTGOSDK/src/Resources/Bootstrapper.cs b/MTGOSDK/src/Resources/Bootstrapper.cs index d9bf8244..3d9f924b 100644 --- a/MTGOSDK/src/Resources/Bootstrapper.cs +++ b/MTGOSDK/src/Resources/Bootstrapper.cs @@ -1,10 +1,15 @@ /** @file + Copyright (c) 2021, Xappy. Copyright (c) 2024, Cory Bennett. All rights reserved. SPDX-License-Identifier: Apache-2.0 **/ using System.Diagnostics; using System.IO; +using System.Net; +using System.Net.Sockets; + +using MTGOSDK.Core.Remoting.Interop; using MTGOSDK.Win32.Extensions; using MTGOSDK.Win32.Injection; @@ -12,6 +17,14 @@ namespace MTGOSDK.Resources; +public enum DiverState +{ + NoDiver, + Alive, + Corpse, + HollowSnapshot +} + public static class Bootstrapper { public static string AppDataDir => @@ -22,6 +35,62 @@ public static class Bootstrapper public static string ExtractDir = typeof(Bootstrapper).Assembly.GetName().Name; + public static DiverState QueryStatus( + Process target, + string diverAddr, + ushort diverPort) + { + DiverCommunicator com = new DiverCommunicator(diverAddr, diverPort); + + // We WANT to check liveness of the diver using HTTP but this might take a + // LOT of time if it is dead (Trying to TCP SYN several times, with a + // timeout between each). So a simple circuit-breaker is implemented + // before that: If we manage to bind to the expected diver endpoint, we + // assume it's not alive + + bool diverPortIsFree = false; + try + { + IPAddress localAddr = IPAddress.Parse(diverAddr); + TcpListener server = new TcpListener(localAddr, diverPort); + server.Start(); + diverPortIsFree = true; + server.Stop(); + } + catch + { + // Had some issues, perhaps it's the diver holding that port. + } + + if (!diverPortIsFree && com.CheckAliveness()) + { + return DiverState.Alive; + } + + // // Check if this is a snapshot created by the diver. + // if (target.Threads.Count == 0) + // return DiverState.HollowSnapshot; + + // Diver isn't alive. It's possible that it was never injected or it was + // injected and killed + bool containsToolkitDll = false; + try + { + containsToolkitDll |= target.Modules.AsEnumerable() + .Any(module => module.ModuleName.Contains("Bootstrapper")); + } + catch + { + // Sometimes this happens because of x32 vs x64 process interaction + } + if (containsToolkitDll) + { + return DiverState.Corpse; + } + + return DiverState.NoDiver; + } + public static void Inject(Process target, ushort diverPort) { #if !MTGOSDKCORE diff --git a/NOTICE b/NOTICE index a10c05cf..96d3c710 100644 --- a/NOTICE +++ b/NOTICE @@ -22,7 +22,8 @@ library, which is licensed under the open-source MIT License with the following copyright information. The below filepaths are derived from these original components of RemoteNET: -RemoteNET: MTGOSDK\src\Core\Remoting +RemoteNET: MTGOSDK\src\Core\Compiler + MTGOSDK\src\Core\Remoting ScubaDiver.API: MTGOSDK\src\Core\Remoting\Interop ScubaDiver: MTGOSDK\lib\ScubaDiver diff --git a/docs/architecture/core-classes.md b/docs/architecture/core-classes.md index 9f010db0..f9347a5b 100644 --- a/docs/architecture/core-classes.md +++ b/docs/architecture/core-classes.md @@ -233,11 +233,11 @@ With the `GetInstance()` method, we can create a dynamic object that fetches a r We can do so using any of the following methods: ```C# -using MTGOSDK.Core.Reflection; // Proxy +using MTGOSDK.Core.Reflection; // TypeProxy using MTGOSDK.Core.Remoting; // RemoteClient -dynamic objB = RemoteClient.GetInstance(new Proxy()); -dynamic objC = RemoteClient.GetInstance(new Proxy(typeof(Bar))); +dynamic objB = RemoteClient.GetInstance(new TypeProxy()); +dynamic objC = RemoteClient.GetInstance(new TypeProxy(typeof(Bar))); dynamic objA = RemoteClient.GetInstance("assembly.namespace.Bar"); ``` @@ -247,7 +247,7 @@ dynamic objA = RemoteClient.GetInstance("assembly.namespace.Bar"); Additionally, multiple instances of the object can be found by using `GetInstances()`, returning an enumerable collection of dynamic objects that represent the remote objects in the client's memory space. ```C# -using MTGOSDK.Core.Reflection; // Proxy +using MTGOSDK.Core.Reflection; // TypeProxy using MTGOSDK.Core.Remoting; // RemoteClient foreach (dynamic obj in RemoteClient.GetInstances("assembly.namespace.Bar")) @@ -260,7 +260,7 @@ foreach (dynamic obj in RemoteClient.GetInstances("assembly.namespace.Bar")) Creating a new instance of a remote object is similarly straightforward, using the `CreateInstance()` method to invoke the object's constructor with the specified arguments. This method takes a string parameter that represents the fully qualified name of the object to be created, and an array of objects that represent the arguments to be passed to the constructor. -Below is an example of creating a new instance of a remote object with the `CreateInstance()` method, using the [`Proxy`](MTGOSDK/src/Core/Reflection/Proxy.cs) class to convert the interface type to a string containing the fully qualified name of the object. We'll assume that the `Bar` class has two constructors, one with two arguments and the other with three arguments. +Below is an example of creating a new instance of a remote object with the `CreateInstance()` method, using the [`TypeProxy`](MTGOSDK/src/Core/Reflection/Proxy.cs) class to convert the interface type to a string containing the fully qualified name of the object. We'll assume that the `Bar` class has two constructors, one with two arguments and the other with three arguments. ```C# class Bar : IDisposable @@ -272,16 +272,16 @@ class Bar : IDisposable ``` ```C# -using MTGOSDK.Core.Reflection; // Proxy +using MTGOSDK.Core.Reflection; // TypeProxy using MTGOSDK.Core.Remoting; // RemoteClient // Invoke the first constructor with 2 arguments (A and B). -dynamic objA = RemoteClient.CreateInstance(new Proxy(), 1, "foo"); +dynamic objA = RemoteClient.CreateInstance(new TypeProxy(), 1, "foo"); // Invoke the second constructor with 3 arguments (A, B, and C). -dynamic objB = RemoteClient.CreateInstance(new Proxy(), 2, "bar", "baz"); +dynamic objB = RemoteClient.CreateInstance(new TypeProxy(), 2, "bar", "baz"); // Invoke the first constructor and dispose of the object when out of scope. -using (dynamic objC = RemoteClient.CreateInstance(new Proxy(), 1, "quz")) +using (dynamic objC = RemoteClient.CreateInstance(new TypeProxy(), 1, "quz")) { // Do something with objC. } @@ -480,15 +480,15 @@ Generally we can retrieve these objects using any of the following methods: ```C# using MTGOSDK.API; // ObjectProvider -using MTGOSDK.Core.Reflection; // Proxy +using MTGOSDK.Core.Reflection; // TypeProxy IBar objA = ObjectProvider.Get(); -IBar objB = ObjectProvider.Get(new Proxy()); -IBar objB = ObjectProvider.Get(new Proxy(typeof(IBar))); +IBar objB = ObjectProvider.Get(new TypeProxy()); +IBar objB = ObjectProvider.Get(new TypeProxy(typeof(IBar))); IBar objC = ObjectProvider.Get("assembly.namespace.IBar"); ``` -Here the [`Proxy`](MTGOSDK/src/Core/Reflection/Proxy.cs) type is used to convert the interface type to a string containing the fully qualified name of the interface type. You can also hard-code the string value if you know the fully qualified name ahead of time. +Here the [`TypeProxy`](MTGOSDK/src/Core/Reflection/Proxy.cs) type is used to convert the interface type to a string containing the fully qualified name of the interface type. You can also hard-code the string value if you know the fully qualified name ahead of time. Under the hood, the `Get` method will call the `Bind()` method from [`DLRWrapper`](#dlrwrapper), but it will also cache the object for future use. This is demonstrated in the following example, which uses the `Get` method to retrieve an object of type IBar.