Merge branch 'master' into switch-to-new-socket-lib

This commit is contained in:
rafael-aero
2021-08-25 17:08:53 +02:00
10 changed files with 184 additions and 44 deletions

View File

@@ -581,7 +581,7 @@ namespace ElectronNET.API
/// <param name="relaunchOptions">Options for the relaunch.</param>
public void Relaunch(RelaunchOptions relaunchOptions)
{
BridgeConnector.EmitSync("appRelaunch", relaunchOptions);
BridgeConnector.EmitSync("appRelaunch", JObject.FromObject(relaunchOptions, _jsonSerializer));
}
/// <summary>
@@ -601,7 +601,7 @@ namespace ElectronNET.API
/// </summary>
public void Focus(FocusOptions focusOptions)
{
BridgeConnector.Emit("appFocus", focusOptions);
BridgeConnector.Emit("appFocus", JObject.FromObject(focusOptions, _jsonSerializer));
}
/// <summary>
@@ -891,7 +891,7 @@ namespace ElectronNET.API
/// <param name="userTasks">Array of <see cref="UserTask"/> objects.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Whether the call succeeded.</returns>
public Task<bool> SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default) => BridgeConnector.OnResult<bool>("appSetUserTasks", "appSetUserTasksCompleted", cancellationToken, userTasks);
public Task<bool> SetUserTasksAsync(UserTask[] userTasks, CancellationToken cancellationToken = default) => BridgeConnector.OnResult<bool>("appSetUserTasks", "appSetUserTasksCompleted", cancellationToken, JArray.FromObject(userTasks, _jsonSerializer));
/// <summary>
/// Jump List settings for the application.
@@ -918,7 +918,7 @@ namespace ElectronNET.API
/// <param name="categories">Array of <see cref="JumpListCategory"/> objects.</param>
public void SetJumpList(JumpListCategory[] categories)
{
BridgeConnector.Emit("appSetJumpList", categories);
BridgeConnector.Emit("appSetJumpList", JArray.FromObject(categories, _jsonSerializer));
}
/// <summary>
@@ -1054,7 +1054,7 @@ namespace ElectronNET.API
/// <param name="options"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Result of import. Value of 0 indicates success.</returns>
public Task<int> ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default) => BridgeConnector.OnResult<int>("appImportCertificate", "appImportCertificateCompleted", cancellationToken, options);
public Task<int> ImportCertificateAsync(ImportCertificateOptions options, CancellationToken cancellationToken = default) => BridgeConnector.OnResult<int>("appImportCertificate", "appImportCertificateCompleted", cancellationToken, JObject.FromObject(options, _jsonSerializer));
/// <summary>
/// Memory and cpu usage statistics of all the processes associated with the app.
@@ -1120,7 +1120,7 @@ namespace ElectronNET.API
/// <param name="cancellationToken">The cancellation token.</param>
public Task<LoginItemSettings> GetLoginItemSettingsAsync(LoginItemSettingsOptions options, CancellationToken cancellationToken = default) =>
options is null ? BridgeConnector.OnResult<LoginItemSettings>("appGetLoginItemSettings", "appGetLoginItemSettingsCompleted", cancellationToken)
: BridgeConnector.OnResult<LoginItemSettings>("appGetLoginItemSettings", "appGetLoginItemSettingsCompleted", cancellationToken, options);
: BridgeConnector.OnResult<LoginItemSettings>("appGetLoginItemSettings", "appGetLoginItemSettingsCompleted", cancellationToken, JObject.FromObject(options, _jsonSerializer));
/// <summary>
/// Set the app's login item settings.
@@ -1130,7 +1130,7 @@ namespace ElectronNET.API
/// <param name="loginSettings"></param>
public void SetLoginItemSettings(LoginSettings loginSettings)
{
BridgeConnector.Emit("appSetLoginItemSettings", loginSettings);
BridgeConnector.Emit("appSetLoginItemSettings", JObject.FromObject(loginSettings, _jsonSerializer));
}
/// <summary>
@@ -1179,7 +1179,7 @@ namespace ElectronNET.API
/// <param name="options">About panel options.</param>
public void SetAboutPanelOptions(AboutPanelOptions options)
{
BridgeConnector.Emit("appSetAboutPanelOptions", options);
BridgeConnector.Emit("appSetAboutPanelOptions", JObject.FromObject(options, _jsonSerializer));
}
/// <summary>
@@ -1243,5 +1243,10 @@ namespace ElectronNET.API
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action<object> fn) => Events.Instance.Once(ModuleName, eventName, fn);
private readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
}
}

View File

@@ -1682,7 +1682,7 @@ namespace ElectronNET.API
public void SetMenu(MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
BridgeConnector.Emit("browserWindowSetMenu", Id, menuItems);
BridgeConnector.Emit("browserWindowSetMenu", Id, JArray.FromObject(menuItems, _jsonSerializer));
_items.AddRange(menuItems);
BridgeConnector.Off("windowMenuItemClicked");
@@ -1788,7 +1788,7 @@ namespace ElectronNET.API
});
thumbarButtons.AddThumbarButtonsId();
BridgeConnector.Emit("browserWindowSetThumbarButtons", Id, thumbarButtons);
BridgeConnector.Emit("browserWindowSetThumbarButtons", Id, JArray.FromObject(thumbarButtons, _jsonSerializer));
_thumbarButtons.Clear();
_thumbarButtons.AddRange(thumbarButtons);
@@ -2003,5 +2003,11 @@ namespace ElectronNET.API
{
BridgeConnector.Emit("browserWindow-setBrowserView", Id, browserView.Id);
}
private static readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

View File

@@ -138,7 +138,7 @@ namespace ElectronNET.API
public void SetMenu(MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
BridgeConnector.Emit("dock-setMenu", menuItems);
BridgeConnector.Emit("dock-setMenu", JArray.FromObject(menuItems, _jsonSerializer));
_items.AddRange(menuItems);
BridgeConnector.Off("dockMenuItemClicked");
@@ -146,7 +146,6 @@ namespace ElectronNET.API
MenuItem menuItem = _items.GetMenuItem(id);
menuItem?.Click();
});
}
/// <summary>
@@ -163,5 +162,11 @@ namespace ElectronNET.API
{
BridgeConnector.Emit("dock-setIcon", image);
}
private static readonly JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

View File

@@ -207,6 +207,27 @@ namespace ElectronNET.API
}
}
/// <summary>
/// Log a message to the console output pipe. This is used when running with "detachedProcess" : true on the electron.manifest.json,
/// as in that case we can't open pipes to read the console output from the child process anymore
/// </summary>
/// <param name="text">Message to log</param>
public static void ConsoleLog(string text)
{
BridgeConnector.Emit("console-stdout", text);
}
/// <summary>
/// Log a message to the console error pipe. This is used when running with "detachedProcess" : true on the electron.manifest.json,
/// as in that case we can't open pipes to read the console output from the child process anymore
/// </summary>
/// <param name="text">Message to log</param>
public static void ConsoleError(string text)
{
BridgeConnector.Emit("console-stderr", text);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),

View File

@@ -58,7 +58,7 @@ namespace ElectronNET.API
menuItems.AddMenuItemsId();
menuItems.AddSubmenuTypes();
BridgeConnector.Emit("menu-setApplicationMenu", menuItems);
BridgeConnector.Emit("menu-setApplicationMenu", JArray.FromObject(menuItems, _jsonSerializer));
_menuItems.AddRange(menuItems);
BridgeConnector.Off("menuItemClicked");
@@ -87,7 +87,7 @@ namespace ElectronNET.API
menuItems.AddMenuItemsId();
menuItems.AddSubmenuTypes();
BridgeConnector.Emit("menu-setContextMenu", browserWindow.Id, menuItems);
BridgeConnector.Emit("menu-setContextMenu", browserWindow.Id, JArray.FromObject(menuItems, _jsonSerializer));
if (!_contextMenuItems.ContainsKey(browserWindow.Id))
{
@@ -112,5 +112,11 @@ namespace ElectronNET.API
{
BridgeConnector.Emit("menu-contextMenuPopup", browserWindow.Id);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

View File

@@ -242,7 +242,7 @@ namespace ElectronNET.API
public void Show(string image, MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
BridgeConnector.Emit("create-tray", image, menuItems);
BridgeConnector.Emit("create-tray", image, JArray.FromObject(menuItems, _jsonSerializer));
_items.Clear();
_items.AddRange(menuItems);
@@ -324,33 +324,39 @@ namespace ElectronNET.API
public Task<bool> IsDestroyedAsync() => BridgeConnector.OnResult<bool>("tray-isDestroyed", "tray-isDestroyedCompleted");
private const string ModuleName = "tray";
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void On(string eventName, Action fn)
=> Events.Instance.On(ModuleName, eventName, fn);
public void On(string eventName, Action fn) => Events.Instance.On(ModuleName, eventName, fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void On(string eventName, Action<object> fn)
=> Events.Instance.On(ModuleName, eventName, fn);
public void On(string eventName, Action<object> fn) => Events.Instance.On(ModuleName, eventName, fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action fn)
=> Events.Instance.Once(ModuleName, eventName, fn);
public void Once(string eventName, Action fn) => Events.Instance.Once(ModuleName, eventName, fn);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action<object> fn)
=> Events.Instance.Once(ModuleName, eventName, fn);
public void Once(string eventName, Action<object> fn) => Events.Instance.Once(ModuleName, eventName, fn);
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
}
}

View File

@@ -150,6 +150,7 @@ namespace ElectronNET.API
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
BridgeConnector.Emit("createBrowserWindow", JObject.FromObject(options, ownjsonSerializer), loadUrl);
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.InteropServices;
@@ -6,6 +7,33 @@ namespace ElectronNET.CLI
{
public class ProcessHelper
{
private static ConcurrentDictionary<Process, bool> _activeProcess = new();
public static void KillActive()
{
foreach(var kv in _activeProcess)
{
if (!kv.Key.HasExited)
{
try
{
kv.Key.CloseMainWindow();
}
catch
{
}
try
{
kv.Key.Kill(true);
}
catch
{
}
}
}
}
public static int CmdExecute(string command, string workingDirectoryPath, bool output = true, bool waitForExit = true)
{
using (Process cmd = new Process())
@@ -43,7 +71,11 @@ namespace ElectronNET.CLI
if (waitForExit)
{
_activeProcess[cmd] = true;
cmd.WaitForExit();
_activeProcess.TryRemove(cmd, out _);
}
return cmd.ExitCode;

View File

@@ -19,6 +19,12 @@ namespace ElectronNET.CLI
Environment.Exit(-1);
}
Console.CancelKeyPress += (s,e) =>
{
ProcessHelper.KillActive();
Environment.Exit(-1);
};
ICommand command = null;
switch (args[0])

View File

@@ -5,6 +5,7 @@ const path = require('path');
const cProcess = require('child_process').spawn;
const portscanner = require('portscanner');
const { imageSize } = require('image-size');
let io, server, browserWindows, ipc, apiProcess, loadURL;
let appApi, menu, dialogApi, notification, tray, webContents;
let globalShortcut, shellApi, screen, clipboard, autoUpdater;
@@ -101,7 +102,16 @@ app.on('ready', () => {
app.on('quit', async (event, exitCode) => {
await server.close();
apiProcess.kill();
var detachedProcess = false;
if (manifestJsonFile.hasOwnProperty('detachedProcess')) {
detachedProcess = manifestJsonFile.detachedProcess;
}
if (!detachedProcess) {
apiProcess.kill();
}
});
function isSplashScreenEnabled() {
@@ -141,7 +151,7 @@ function startSplashScreen() {
if (manifestJsonFile.splashscreen.hasOwnProperty('timeout')) {
var timeout = manifestJsonFile.splashscreen.timeout;
setTimeout((t) => {
if (splashScreen != null ) {
if (splashScreen) {
splashScreen.hide();
}
}, timeout);
@@ -261,6 +271,14 @@ function startSocketApiBridge(port) {
}
});
socket.on('console-stdout', (data) => {
console.log(`stdout: ${data.toString()}`);
});
socket.on('console-stderr', (data) => {
console.log(`stderr: ${data.toString()}`);
});
try {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
@@ -296,7 +314,7 @@ function startAspCoreBackend(electronPort) {
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`];
const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`];
let binaryFile = manifestJsonFile.executable;
const os = require('os');
@@ -304,17 +322,31 @@ function startAspCoreBackend(electronPort) {
binaryFile = binaryFile + '.exe';
}
var detachedProcess = false;
var stdioopt = 'pipe';
if (manifestJsonFile.hasOwnProperty('detachedProcess')) {
detachedProcess = manifestJsonFile.detachedProcess;
if (detachedProcess) {
stdioopt = 'ignore';
}
}
let binFilePath = path.join(currentBinPath, binaryFile);
var options = { cwd: currentBinPath };
var options = { cwd: currentBinPath, detached: detachedProcess, stdio: stdioopt };
apiProcess = cProcess(binFilePath, parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
if (!detachedProcess) {
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
apiProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data.toString()}`);
});
apiProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data.toString()}`);
});
}
apiProcess.on('close', (code) => {
console.log(`ASP.NET Process exited with code ${code}`);
@@ -323,6 +355,11 @@ function startAspCoreBackend(electronPort) {
app.exit(code);
}
});
if (detachedProcess) {
console.log('Detached from ASP.NET process');
apiProcess.unref();
}
}
}
@@ -339,21 +376,31 @@ function startAspCoreBackendWithWatch(electronPort) {
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`];
const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`, `/electronPID=${process.pid}`];
var detachedProcess = false;
var stdioopt = 'pipe';
if (manifestJsonFile.hasOwnProperty('detachedProcess')) {
detachedProcess = manifestJsonFile.detachedProcess;
if (detachedProcess) {
stdioopt = 'ignore';
}
}
var options = { cwd: currentBinPath, env: process.env, detached: detachedProcess, stdio: stdioopt };
var options = {
cwd: currentBinPath,
env: process.env,
};
apiProcess = cProcess('dotnet', parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
if (!detachedProcess) {
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
apiProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data.toString()}`);
});
apiProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data.toString()}`);
});
}
apiProcess.on('close', (code) => {
console.log(`ASP.NET Process exited with code ${code}`);
@@ -362,6 +409,11 @@ function startAspCoreBackendWithWatch(electronPort) {
app.exit(code);
}
});
if (detachedProcess) {
console.log('Detached from ASP.NET process');
apiProcess.unref();
}
}
}