Skip to content

Commit e9976c3

Browse files
committed
various fixes and improvements to full-proof further
1 parent 93fa340 commit e9976c3

9 files changed

Lines changed: 145 additions & 50 deletions

File tree

.vscode/launch.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": ".NET Core Launch (console)",
6+
"type": "coreclr",
7+
"request": "launch",
8+
"preLaunchTask": "build",
9+
"program": "${workspaceFolder}/bin/Debug/net8.0/GTerm.dll",
10+
"args": [],
11+
"cwd": "${workspaceFolder}",
12+
"console": "externalTerminal",
13+
"stopAtEntry": false,
14+
"requireExactSource": false
15+
},
16+
{
17+
"name": ".NET Core Attach",
18+
"type": "coreclr",
19+
"request": "attach"
20+
}
21+
]
22+
}

.vscode/tasks.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "build",
6+
"command": "dotnet",
7+
"type": "process",
8+
"args": [
9+
"build",
10+
"${workspaceFolder}/GTerm.sln",
11+
"--configuration",
12+
"Debug",
13+
"/property:GenerateFullPaths=true",
14+
"/consoleloggerparameters:NoSummary;ForceNoAlign"
15+
],
16+
"problemMatcher": "$msCompile",
17+
"group": {
18+
"kind": "build",
19+
"isDefault": true
20+
}
21+
},
22+
{
23+
"label": "build-release",
24+
"command": "dotnet",
25+
"type": "process",
26+
"args": [
27+
"build",
28+
"${workspaceFolder}/GTerm.sln",
29+
"--configuration",
30+
"Release",
31+
"/property:GenerateFullPaths=true",
32+
"/consoleloggerparameters:NoSummary;ForceNoAlign"
33+
],
34+
"problemMatcher": "$msCompile"
35+
},
36+
{
37+
"label": "publish",
38+
"command": "dotnet",
39+
"type": "process",
40+
"args": [
41+
"publish",
42+
"${workspaceFolder}/GTerm.sln",
43+
"/property:GenerateFullPaths=true",
44+
"/consoleloggerparameters:NoSummary;ForceNoAlign"
45+
],
46+
"problemMatcher": "$msCompile"
47+
},
48+
{
49+
"label": "watch",
50+
"command": "dotnet",
51+
"type": "process",
52+
"args": [
53+
"watch",
54+
"run",
55+
"--project",
56+
"${workspaceFolder}/GTerm.sln"
57+
],
58+
"problemMatcher": "$msCompile"
59+
}
60+
]
61+
}

Extensions/ProcessExtensions.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ public static class ProcessExtensions
88
public static Process? GetParent(this Process process) {
99
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return null;
1010

11-
return ParentProcessUtilities.GetParentProcess(process.Handle);
11+
try {
12+
return ParentProcessUtilities.GetParentProcess(process.Handle);
13+
}
14+
catch (Exception ex)
15+
{
16+
LocalLogger.WriteLine($"Failed to get parent process: {ex.Message}");
17+
return null;
18+
}
1219
}
1320
}
14-
}
21+
}

Extensions/Win32Extensions.cs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,55 @@
44

55
namespace GTerm.Extensions
66
{
7-
internal class Win32Extensions
7+
internal partial class Win32Extensions
88
{
99
internal const int SW_MINIMIZE = 6;
1010
internal const int SW_HIDE = 0;
1111

1212
internal delegate bool ConsoleEventDelegate(int eventType);
1313

14-
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
15-
internal static extern IntPtr GetConsoleWindow();
14+
[LibraryImport("Kernel32.dll", SetLastError = true)]
15+
[UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
16+
internal static partial IntPtr GetConsoleWindow();
1617

17-
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
18+
[LibraryImport("User32.dll", SetLastError = true)]
19+
[UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
1820
[return: MarshalAs(UnmanagedType.Bool)]
19-
internal static extern bool ShowWindow([In] IntPtr hWnd, [In] int nCmdShow);
21+
internal static partial bool ShowWindow(IntPtr hWnd, int nCmdShow);
2022

21-
[DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
23+
[LibraryImport("User32.dll", SetLastError = true)]
24+
[UnmanagedCallConv(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
2225
[return: MarshalAs(UnmanagedType.Bool)]
23-
internal static extern bool IsWindowVisible([In] IntPtr hWnd);
26+
internal static partial bool IsWindowVisible(IntPtr hWnd);
2427

25-
[DllImport("kernel32.dll", SetLastError = true)]
26-
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
28+
[LibraryImport("kernel32.dll", SetLastError = true)]
29+
[return: MarshalAs(UnmanagedType.Bool)]
30+
internal static partial bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, [MarshalAs(UnmanagedType.Bool)] bool add);
2731

2832
internal enum WinMessages : uint
2933
{
3034
/// <summary>
31-
/// An application sends the WM_SETICON message to associate a new large or small icon with a window.
32-
/// The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption.
35+
/// An application sends the WM_SETICON message to associate a new large or small icon with a window.
36+
/// The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption.
3337
/// </summary>
3438
SETICON = 0x0080,
3539
}
3640

37-
[DllImport("user32.dll", CharSet = CharSet.Auto)]
38-
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
41+
[LibraryImport("user32.dll", EntryPoint = "SendMessageW")]
42+
private static partial IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
3943

44+
[System.Runtime.Versioning.SupportedOSPlatform("windows6.1")]
4045
private static void SetWindowIcon(System.Drawing.Icon icon)
4146
{
42-
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
43-
44-
IntPtr mwHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
47+
IntPtr mwHandle = Process.GetCurrentProcess().MainWindowHandle;
4548
SendMessage(mwHandle, (int)WinMessages.SETICON, 0, icon.Handle);
4649
SendMessage(mwHandle, (int)WinMessages.SETICON, 1, icon.Handle);
4750
}
4851

4952
internal static void SetConsoleIcon(string iconFilePath)
5053
{
51-
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
52-
54+
if (!OperatingSystem.IsWindowsVersionAtLeast(6, 1)) return;
55+
5356
if (!string.IsNullOrEmpty(iconFilePath))
5457
{
5558
System.Drawing.Icon? icon = System.Drawing.Icon.ExtractAssociatedIcon(iconFilePath);
@@ -65,7 +68,7 @@ internal static void SetConsoleIcon(string iconFilePath)
6568
/// A utility class to determine a process parent.
6669
/// </summary>
6770
[StructLayout(LayoutKind.Sequential)]
68-
internal struct ParentProcessUtilities
71+
internal partial struct ParentProcessUtilities
6972
{
7073
// These members must match PROCESS_BASIC_INFORMATION
7174
internal IntPtr Reserved1;
@@ -75,8 +78,8 @@ internal struct ParentProcessUtilities
7578
internal IntPtr UniqueProcessId;
7679
internal IntPtr InheritedFromUniqueProcessId;
7780

78-
[DllImport("ntdll.dll")]
79-
private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
81+
[LibraryImport("ntdll.dll")]
82+
private static partial int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
8083

8184
/// <summary>
8285
/// Gets the parent process of a specified process.
@@ -85,8 +88,8 @@ internal struct ParentProcessUtilities
8588
/// <returns>An instance of the Process class.</returns>
8689
public static Process? GetParentProcess(IntPtr handle)
8790
{
88-
ParentProcessUtilities pbi = new ParentProcessUtilities();
89-
int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out int returnLength);
91+
ParentProcessUtilities pbi = new();
92+
int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out int _);
9093
if (status != 0)
9194
throw new Win32Exception(status);
9295

GTerm.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<TargetFramework>net8.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
8+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
89
</PropertyGroup>
910

1011
<ItemGroup>

GTerm.sln

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
2-
Microsoft Visual Studio Solution File, Format Version 12.00
1+
Microsoft Visual Studio Solution File, Format Version 12.00
32
# Visual Studio Version 17
43
VisualStudioVersion = 17.11.35222.181
54
MinimumVisualStudioVersion = 10.0.40219.1
@@ -11,8 +10,8 @@ Global
1110
Release|Any CPU = Release|Any CPU
1211
EndGlobalSection
1312
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14-
{AF6A87E8-0206-406C-8FD6-BC5A9E4FA10F}.Debug|Any CPU.ActiveCfg = Release|Any CPU
15-
{AF6A87E8-0206-406C-8FD6-BC5A9E4FA10F}.Debug|Any CPU.Build.0 = Release|Any CPU
13+
{AF6A87E8-0206-406C-8FD6-BC5A9E4FA10F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14+
{AF6A87E8-0206-406C-8FD6-BC5A9E4FA10F}.Debug|Any CPU.Build.0 = Debug|Any CPU
1615
{AF6A87E8-0206-406C-8FD6-BC5A9E4FA10F}.Release|Any CPU.ActiveCfg = Release|Any CPU
1716
{AF6A87E8-0206-406C-8FD6-BC5A9E4FA10F}.Release|Any CPU.Build.0 = Release|Any CPU
1817
EndGlobalSection
@@ -22,4 +21,4 @@ Global
2221
GlobalSection(ExtensibilityGlobals) = postSolution
2322
SolutionGuid = {F7F2E0B7-31DC-4B45-AEA1-6296545AF74F}
2423
EndGlobalSection
25-
EndGlobal
24+
EndGlobal

GmodInterop.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal class GmodInterop
1111
{
1212
private const string GMOD_ID = "4000";
1313

14-
private static Process? GetGmodProcess()
14+
private static Process? GetGmodProcess()
1515
=> Process.GetProcessesByName("gmod").FirstOrDefault();
1616

1717
private static bool TryGetSteamVDFPath(out string vdfPath)
@@ -51,22 +51,22 @@ private static bool TryGetSteamVDFPath(out string vdfPath)
5151
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
5252
{
5353
string? homeDir = Environment.GetEnvironmentVariable("HOME");
54-
if (homeDir != null)
54+
if (homeDir != null)
5555
{
5656
vdfPath = Path.Join(homeDir, "/Library/Application Support/Steam/steamapps/libraryfolders.vdf");
5757
return File.Exists(vdfPath);
5858
}
5959
}
60-
else
60+
else
6161
{
6262
string? homeDir = Environment.GetEnvironmentVariable("HOME");
63-
if (homeDir != null)
63+
if (homeDir != null)
6464
{
6565
vdfPath = Path.Join(homeDir, "/.steam/steam/steamapps/libraryfolders.vdf");
66-
if (!File.Exists(vdfPath))
66+
if (!File.Exists(vdfPath))
6767
{
6868
vdfPath = Path.Join(homeDir, "/.local/share/Steam/steamapps/libraryfolders.vdf");
69-
if (!File.Exists(vdfPath))
69+
if (!File.Exists(vdfPath))
7070
{
7171
// flatpak
7272
vdfPath = Path.Join(homeDir, "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/libraryfolders.vdf");
@@ -106,7 +106,7 @@ private static bool TryGetMountedBeta(out bool isX64)
106106
}
107107
catch (Exception ex)
108108
{
109-
Console.WriteLine($"Could not find Garry's Mod manifest, assuming branch\n" + ex.Message);
109+
LocalLogger.WriteLine($"Could not find Garry's Mod manifest, assuming branch\n" + ex.Message);
110110
}
111111
}
112112

@@ -133,7 +133,7 @@ internal static bool TryGetGmodPath(out string gmodPath, bool toBin = true)
133133
return true;
134134
}
135135

136-
int index = path.IndexOf("GarrysMod/bin");
136+
int index = path.IndexOf("GarrysMod");
137137
gmodPath = Path.Combine(path[..index], "GarrysMod");
138138
return true;
139139
}
@@ -163,8 +163,8 @@ internal static bool TryGetGmodPath(out string gmodPath, bool toBin = true)
163163
{
164164
if (gotBeta)
165165
{
166-
gmodPath = isX64
167-
? Path.Combine(gmodPathDir, "bin/win64/gmod.exe")
166+
gmodPath = isX64
167+
? Path.Combine(gmodPathDir, "bin/win64/gmod.exe")
168168
: Path.Combine(gmodPathDir, "bin/gmod.exe");
169169
}
170170
else
@@ -180,7 +180,7 @@ internal static bool TryGetGmodPath(out string gmodPath, bool toBin = true)
180180

181181
if (!File.Exists(gmodPath))
182182
gmodPath = Path.Combine(gmodPathDir, "hl2.exe");
183-
}
183+
}
184184
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
185185
{
186186
gmodPath = Path.Combine(gmodPathDir, "hl2_osx");
@@ -198,7 +198,7 @@ internal static bool TryGetGmodPath(out string gmodPath, bool toBin = true)
198198
gmodPath = Path.Combine(gmodPathDir, "hl2_linux");
199199
if (!File.Exists(gmodPath))
200200
gmodPath = Path.Combine(gmodPathDir, "srcds");
201-
}
201+
}
202202
}
203203
}
204204

@@ -224,7 +224,7 @@ private static string GetBinaryFileName(bool isX64)
224224
string moduleName = "gmsv_xconsole_";
225225
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
226226
{
227-
moduleName += (isX64 ? "win64" : "win32");
227+
moduleName += isX64 ? "win64" : "win32";
228228
}
229229
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
230230
{
@@ -269,7 +269,7 @@ private static async Task<bool> InstallBinary(bool isX64, string luaBinPath)
269269
private static bool IsGmodX64(string gmodBinPath)
270270
{
271271
// Base assumption in case it fails later (windows can do x86 and x64, linux/mac only x64)
272-
bool isX64 = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
272+
bool isX64 = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
273273
|| gmodBinPath.Contains("win64", StringComparison.CurrentCulture)
274274
|| gmodBinPath.Contains("linux64", StringComparison.CurrentCulture);
275275

@@ -298,7 +298,7 @@ private static bool IsGmodX64(string gmodBinPath)
298298
Directory.CreateDirectory(luaBinPath);
299299
modifiedGameFiles = true;
300300
}
301-
301+
302302
bool isX64 = IsGmodX64(gmodBinPath);
303303
bool justInstalledBin = await InstallBinary(isX64, luaBinPath);
304304
if (justInstalledBin) {
@@ -322,7 +322,7 @@ private static bool IsGmodX64(string gmodBinPath)
322322
AnsiConsole.MarkupLine("[white on red]Garry's Mod needs to be restarted for GTerm to work properly.[/]");
323323
}
324324
}
325-
325+
326326
success = true;
327327
}
328328
catch (Exception ex)
@@ -345,7 +345,7 @@ private static bool ConsoleEventCallback(int eventType)
345345
// Keeps it from getting garbage collected
346346
private static Win32Extensions.ConsoleEventDelegate? handler;
347347
private static Process? GmodProcess;
348-
348+
349349
/// <summary>
350350
/// Launches gmod in textmode
351351
/// </summary>

LocalLogger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal static void WriteLine(params object[] args)
1212
try {
1313
string outMsg = $"{DateTime.Now:hh:mm:ss} | {string.Join("\t", args.Select(x => x.ToString()))}\n";
1414
File.AppendAllText(Path.Combine(gtermDir, "gterm.log"), outMsg);
15-
}
15+
}
1616
catch {}
1717
}
1818
}

Program.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ static void Main(string[] args)
5353
Config = new Config(args);
5454

5555
Process? parent = curProc.GetParent();
56-
if (parent?.MainModule?.ModuleName == "gmod.exe")
56+
LocalLogger.WriteLine($"Parent process: {parent?.ProcessName}");
57+
if (parent?.ProcessName.Equals("gmod", StringComparison.OrdinalIgnoreCase) == true)
5758
{
5859
LocalLogger.WriteLine("Started from Gmod!");
5960
Config.StartAsGmod = false; // this cannot be true if gmod already runs GTerm as a child process
@@ -68,7 +69,8 @@ static void Main(string[] args)
6869

6970
LocalLogger.WriteLine("Gmod crashed, attempting to restart!");
7071
ProcessStartInfo oldStartInfo = parent.StartInfo;
71-
if (GmodInterop.TryGetGmodPath(out string gmodBinpath)) {
72+
if (GmodInterop.TryGetGmodPath(out string gmodBinpath))
73+
{
7274
oldStartInfo.FileName = gmodBinpath;
7375
LocalLogger.WriteLine("Restarting Gmod!");
7476
Process.Start(parent.StartInfo); // reboot gmod because crash and it was the owning process

0 commit comments

Comments
 (0)