Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework Startup Args #946

Merged
merged 7 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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