URI Scheme

This commit is contained in:
Natsumi
2021-09-27 10:43:16 +13:00
parent 2833486091
commit e007d9d23e
8 changed files with 261 additions and 0 deletions

View File

@@ -337,6 +337,13 @@ namespace VRCX
VRCXVR._browser2.ExecuteScriptAsync($"$app.{function}", json);
}
public string GetLaunchCommand()
{
string command = StartupArgs.LaunchCommand;
StartupArgs.LaunchCommand = string.Empty;
return command;
}
public void SetStartup(bool enabled)
{
try

73
IPCClient.cs Normal file
View File

@@ -0,0 +1,73 @@
// Copyright(c) 2019-2021 pypy. All rights reserved.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
using CefSharp;
using System;
using System.IO.Pipes;
using System.Text;
namespace VRCX
{
class IPCClient
{
private NamedPipeServerStream _ipcServer;
private byte[] _recvBuffer = new byte[1024 * 8];
private string _currentPacket;
public IPCClient(NamedPipeServerStream ipcServer)
{
_ipcServer = ipcServer;
}
public void BeginRead()
{
_ipcServer.BeginRead(_recvBuffer, 0, _recvBuffer.Length, OnRead, _ipcServer);
}
private void OnRead(IAsyncResult asyncResult)
{
try
{
var bytesRead = _ipcServer.EndRead(asyncResult);
if (bytesRead <= 0)
{
_ipcServer.Close();
return;
}
_currentPacket += Encoding.UTF8.GetString(_recvBuffer, 0, bytesRead);
if (_currentPacket[_currentPacket.Length - 1] == (char)0x00)
{
var packets = _currentPacket.Split((char)0x00);
foreach (var packet in packets)
{
if (string.IsNullOrEmpty(packet))
continue;
MainForm.Instance.Browser.ExecuteScriptAsync("$app.ipcEvent", packet);
}
_currentPacket = string.Empty;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
BeginRead();
}
public static void OnSend(IAsyncResult asyncResult)
{
var ipcClient = (NamedPipeClientStream)asyncResult.AsyncState;
ipcClient.EndWrite(asyncResult);
}
}
}

48
IPCServer.cs Normal file
View File

@@ -0,0 +1,48 @@
// Copyright(c) 2019-2021 pypy. All rights reserved.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
using System;
using System.IO.Pipes;
namespace VRCX
{
class IPCServer
{
public static readonly IPCServer Instance;
static IPCServer()
{
Instance = new IPCServer();
}
public void Init()
{
new IPCServer().CreateIPCServer();
}
public void CreateIPCServer()
{
var ipcServer = new NamedPipeServerStream("vrcx-ipc", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
ipcServer.BeginWaitForConnection(asyncResult => DoAccept(asyncResult), ipcServer);
}
private void DoAccept(IAsyncResult asyncResult)
{
var ipcServer = (NamedPipeServerStream)asyncResult.AsyncState;
try
{
ipcServer.EndWaitForConnection(asyncResult);
}
catch (Exception e)
{
Console.WriteLine(e);
}
new IPCClient(ipcServer).BeginRead();
CreateIPCServer();
}
}
}

View File

@@ -145,6 +145,14 @@ Section "Install" SecInstall
CreateShortCut "$SMPROGRAMS\VRCX.lnk" "$INSTDIR\VRCX.exe"
ApplicationID::Set "$SMPROGRAMS\VRCX.lnk" "VRCX"
WriteRegStr HKCU "Software\Classes\vrcx" "" "URL:vrcx"
WriteRegStr HKCU "Software\Classes\vrcx" "FriendlyTypeName" "VRCX"
WriteRegStr HKCU "Software\Classes\vrcx" "URL Protocol" ""
WriteRegExpandStr HKCU "Software\Classes\vrcx\DefaultIcon" "" "$INSTDIR\VRCX.ico"
WriteRegStr HKCU "Software\Classes\vrcx\shell" "" "open"
WriteRegStr HKCU "Software\Classes\vrcx\shell\open" "FriendlyAppName" "VRCX"
WriteRegStr HKCU "Software\Classes\vrcx\shell\open\command" "" '"D:\WindowsFiles\Documents\git\VRCX\bin\x64\Release\VRCX.exe" /uri="%1" /params="%2 %3 %4"'
${If} ${Silent}
SetOutPath $INSTDIR
ShellExecAsUser::ShellExecAsUser "" "$INSTDIR\VRCX.exe" ""
@@ -169,6 +177,7 @@ Section "Uninstall"
DeleteRegKey HKLM "Software\VRCX"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VRCX"
DeleteRegKey HKCU "Software\Classes\vrcx"
Delete "$SMPROGRAMS\VRCX.lnk"

View File

@@ -53,6 +53,7 @@ namespace VRCX
private static void Run()
{
StartupArgs.ArgsCheck();
Update.Check();
Application.EnableVisualStyles();
@@ -66,6 +67,7 @@ namespace VRCX
LogWatcher.Instance.Init();
CefService.Instance.Init();
IPCServer.Instance.Init();
VRCXVR.Instance.Init();
Application.Run(new MainForm());
WebApi.Instance.SaveCookies();

72
StartupArgs.cs Normal file
View File

@@ -0,0 +1,72 @@
// Copyright(c) 2019-2021 pypy. All rights reserved.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
using System;
using System.Diagnostics;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Text;
namespace VRCX
{
class StartupArgs
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);
public static string LaunchCommand;
public static void ArgsCheck()
{
string[] args = Environment.GetCommandLineArgs();
if (args.Length == 0)
return;
foreach (string arg in args)
{
if (arg.Length > 12 && arg.Substring(0, 12) == "/uri=vrcx://")
{
LaunchCommand = arg.Substring(12);
ProcessCheck(LaunchCommand);
}
}
}
private static void ProcessCheck(string command)
{
Process currentProcess = Process.GetCurrentProcess();
Process[] processList = Process.GetProcessesByName("VRCX");
if (processList.Length > 1)
{
new IPCServer().CreateIPCServer();
var ipcClient = new NamedPipeClientStream(".", "vrcx-ipc", PipeDirection.InOut);
ipcClient.Connect();
if (ipcClient.IsConnected)
{
var buffer = Encoding.UTF8.GetBytes($"{{\"type\":\"LaunchCommand\",\"command\":\"{command}\"}}" + (char)0x00);
ipcClient.BeginWrite(buffer, 0, buffer.Length, IPCClient.OnSend, ipcClient);
}
foreach (Process process in processList)
{
if (process.Id != currentProcess.Id)
{
IntPtr handle = process.MainWindowHandle;
ShowWindow(handle, 9);
SetForegroundWindow(handle);
}
}
Environment.Exit(0);
}
}
}
}

View File

@@ -81,6 +81,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AssetBundleCacher.cs" />
<Compile Include="IPCClient.cs" />
<Compile Include="IPCServer.cs" />
<Compile Include="StartupArgs.cs" />
<Compile Include="Update.cs" />
<Compile Include="CefService.cs" />
<Compile Include="Discord.cs" />

View File

@@ -15582,6 +15582,53 @@ speechSynthesis.getVoices();
return user.currentAvatarImageUrl;
};
$app.methods.ipcEvent = function (json) {
try {
var data = JSON.parse(json);
} catch {
console.error(`IPC invalid JSON, ${json}`);
}
switch (data.type) {
case 'Ping':
this.eventPing(data);
break;
case 'LaunchCommand':
this.eventLaunchCommand(data.command);
break;
}
};
API.$on('LOGIN', async function () {
var command = await AppApi.GetLaunchCommand();
if (command) {
$app.eventLaunchCommand(command);
}
});
$app.methods.eventLaunchCommand = function (command) {
if (!API.isLoggedIn) {
return;
}
var args = command.split('/');
var command = args[0];
var commandArg = args[1];
switch (command) {
case 'world':
this.showWorldDialog(commandArg);
break;
case 'avatar':
this.showAvatarDialog(commandArg);
break;
case 'user':
this.showUserDialog(commandArg);
break;
}
};
$app.methods.eventPing = function (data) {
console.log('IPC Ping', data.version);
};
$app = new Vue($app);
window.$app = $app;
})();