Skip to content

Commit

Permalink
Rework Startup Args (#946)
Browse files Browse the repository at this point in the history
* Rework startup args

* Preserve previous startup args on re-launch

* Ignore subprocess when checking for duplicate processes

* Cleanup code

* Remove extra process list grabbing

* Use `IsUpgradePrefix` when using `RestartApplication`

* Change `ProxyServerPrefix` to `ProxyUrlPrefix`
  • Loading branch information
DubyaDude authored Oct 21, 2024
1 parent ddc1604 commit 4f34e2d
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 40 deletions.
25 changes: 21 additions & 4 deletions Dotnet/AppApi/AppApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,16 +278,33 @@ public void DesktopNotification(string BoldText, string Text = "", string Image
}

/// <summary>
/// Restarts the VRCX application for an update by launching a new process with the "/Upgrade" argument and exiting the current process.
/// Restarts the VRCX application for an update by launching a new process with the upgrade argument and exiting the current process.
/// </summary>
public void RestartApplication()
{
List<string> args = [ StartupArgs.VrcxLaunchArguements.IsUpgradePrefix ];

if (StartupArgs.LaunchArguements.IsDebug == true)
{
args.Add(StartupArgs.VrcxLaunchArguements.IsDebugPrefix);
}

if (!string.IsNullOrWhiteSpace(StartupArgs.LaunchArguements.ConfigDirectory))
{
args.Add($"{StartupArgs.VrcxLaunchArguements.ConfigDirectoryPrefix}={StartupArgs.LaunchArguements.ConfigDirectory}");
}

if (!string.IsNullOrWhiteSpace(StartupArgs.LaunchArguements.ProxyUrl))
{
args.Add($"{StartupArgs.VrcxLaunchArguements.ProxyUrlPrefix}={StartupArgs.LaunchArguements.ProxyUrl}");
}

var vrcxProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = Path.Combine(Program.BaseDirectory, "VRCX.exe"),
Arguments = "/Upgrade",
Arguments = string.Join(' ', args),
UseShellExecute = true,
WorkingDirectory = Program.BaseDirectory
}
Expand Down Expand Up @@ -362,8 +379,8 @@ public void ExecuteVrOverlayFunction(string function, string json)
/// <returns>The launch command.</returns>
public string GetLaunchCommand()
{
var command = StartupArgs.LaunchCommand;
StartupArgs.LaunchCommand = string.Empty;
var command = StartupArgs.LaunchArguements.LaunchCommand;
StartupArgs.LaunchArguements.LaunchCommand = string.Empty;
return command;
}

Expand Down
129 changes: 95 additions & 34 deletions Dotnet/StartupArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,132 @@
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.

using CefSharp;
using CefSharp.Internals;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Net;
using System.Linq;
using System.Management;
using System.Text;
using System.Windows.Forms;

namespace VRCX
{
internal class StartupArgs
{
public static string LaunchCommand;
public static string ProxyUrl;
public static Process[] processList;
public static VrcxLaunchArguements LaunchArguements = new();

public static void ArgsCheck()
{
var args = Environment.GetCommandLineArgs();
processList = Process.GetProcessesByName("VRCX");

Debug.Assert(Program.LaunchDebug = true);

var currentProcessArgs = ParseArgs(args);
LaunchArguements = currentProcessArgs;

if (LaunchArguements.IsDebug)
Program.LaunchDebug = true;

if (LaunchArguements.ConfigDirectory != null)
{
if (File.Exists(LaunchArguements.ConfigDirectory))
{
MessageBox.Show("Move your \"VRCX.sqlite3\" into a folder then specify the folder in the launch parameter e.g.\n--config=\"C:\\VRCX\\\"", "--config is now a directory", MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(0);
}

Program.AppDataDirectory = LaunchArguements.ConfigDirectory;
}

var disableClosing = false;

if (LaunchArguements.IsUpgrade || // we're upgrading, allow it
!string.IsNullOrEmpty(CommandLineArgsParser.GetArgumentValue(args, CefSharpArguments.SubProcessTypeArgument))) // we're launching a subprocess, allow it
disableClosing = true;

// if we're launching a second instance with same config directory, focus the first instance then exit
if (!disableClosing && IsDuplicateProcessRunning(LaunchArguements))
{
IPCToMain();
Environment.Exit(0);
}
}

private static VrcxLaunchArguements ParseArgs(string[] args)
{
VrcxLaunchArguements arguements = new VrcxLaunchArguements();
foreach (var arg in args)
{
if (arg == "/Upgrade")
disableClosing = true;
if (arg == VrcxLaunchArguements.IsUpgradePrefix)
arguements.IsUpgrade = true;

if (arg.StartsWith(VrcxLaunchArguements.IsDebugPrefix))
arguements.IsDebug = true;

if (arg.Length > 12 && arg.Substring(0, 12) == "/uri=vrcx://")
LaunchCommand = arg.Substring(12);
if (arg.StartsWith(VrcxLaunchArguements.LaunchCommandPrefix) && arg.Length > VrcxLaunchArguements.LaunchCommandPrefix.Length)
arguements.LaunchCommand = arg.Substring(VrcxLaunchArguements.LaunchCommandPrefix.Length);

if (arg.StartsWith(VrcxLaunchArguements.ConfigDirectoryPrefix) && arg.Length > VrcxLaunchArguements.ConfigDirectoryPrefix.Length)
arguements.ConfigDirectory = arg.Substring(VrcxLaunchArguements.ConfigDirectoryPrefix.Length + 1);

if (arg.StartsWith(VrcxLaunchArguements.ProxyUrlPrefix) && arg.Length > VrcxLaunchArguements.ProxyUrlPrefix.Length)
arguements.ProxyUrl = arg.Substring(VrcxLaunchArguements.ProxyUrlPrefix.Length + 1).Replace("'", string.Empty).Replace("\"", string.Empty);
}
return arguements;
}

internal class VrcxLaunchArguements
{
public const string IsUpgradePrefix = "/Upgrade";
public bool IsUpgrade { get; set; } = false;

public const string IsDebugPrefix = "--debug";
public bool IsDebug { get; set; } = false;

public const string LaunchCommandPrefix = "/uri=vrcx://";
public string LaunchCommand { get; set; } = null;

public const string ConfigDirectoryPrefix = "--config";
public string ConfigDirectory { get; set; } = null;

public const string ProxyUrlPrefix = "--proxy-server";
public string ProxyUrl { get; set; } = null;
}

private static bool IsDuplicateProcessRunning(VrcxLaunchArguements launchArguements)
{
var processes = Process.GetProcessesByName("VRCX");
foreach (var process in processes)
{
var commandLine = string.Empty;

if (arg.Length > 8 && arg.Substring(0, 8) == "--config")
try
{
var filePath = arg.Substring(9);
if (File.Exists(filePath))
using (var searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id))
{
MessageBox.Show("Move your \"VRCX.sqlite3\" into a folder then specify the folder in the launch parameter e.g.\n--config=\"C:\\VRCX\\\"", "--config is now a directory", MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(0);
using (var objects = searcher.Get())
{
commandLine = objects.Cast<ManagementBaseObject>().SingleOrDefault()?["CommandLine"]?.ToString() ?? string.Empty;
}
}
Program.AppDataDirectory = filePath;
}
catch { }

if (arg.Length >= 7 && arg.Substring(0, 7) == "--debug")
Program.LaunchDebug = true;
if (commandLine.Contains(CefSharpArguments.SubProcessTypeArgument)) // ignore subprocesses
{
continue;
}

if (arg.Length >= 16 && arg.Substring(0, 14) == "--proxy-server")
ProxyUrl = arg.Substring(15).Replace("'", string.Empty).Replace("\"", string.Empty);
var processArguements = ParseArgs(commandLine.Split(' '));
if (processArguements.ConfigDirectory == launchArguements.ConfigDirectory)
{
return true;
}
}

var type = CommandLineArgsParser.GetArgumentValue(args, CefSharpArguments.SubProcessTypeArgument);
if (!string.IsNullOrEmpty(type))
disableClosing = true; // we're launching a subprocess, allow it

if (!string.IsNullOrEmpty(Program.AppDataDirectory))
disableClosing = true; // we're launching with a custom config path, allow it

// if we're launching a second instance, focus the first instance then exit
if (!disableClosing && processList.Length > 1)
{
IPCToMain();
Environment.Exit(0);
}
return false;
}

private static void IPCToMain()
Expand All @@ -79,7 +140,7 @@ private static void IPCToMain()

if (ipcClient.IsConnected)
{
var buffer = Encoding.UTF8.GetBytes($"{{\"type\":\"LaunchCommand\",\"command\":\"{LaunchCommand}\"}}" + (char)0x00);
var buffer = Encoding.UTF8.GetBytes($"{{\"type\":\"LaunchCommand\",\"command\":\"{LaunchArguements.LaunchCommand}\"}}" + (char)0x00);
ipcClient.BeginWrite(buffer, 0, buffer.Length, IPCClient.Close, ipcClient);
}
}
Expand Down
4 changes: 2 additions & 2 deletions Dotnet/WebApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ internal void Init()

private void SetProxy()
{
if (!string.IsNullOrEmpty(StartupArgs.ProxyUrl))
ProxyUrl = StartupArgs.ProxyUrl;
if (!string.IsNullOrEmpty(StartupArgs.LaunchArguements.ProxyUrl))
ProxyUrl = StartupArgs.LaunchArguements.ProxyUrl;

if (string.IsNullOrEmpty(ProxyUrl))
{
Expand Down
1 change: 1 addition & 0 deletions VRCX.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
Expand Down

0 comments on commit 4f34e2d

Please sign in to comment.