mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-09-22 23:15:25 +00:00
Merge branch 'master' into switch-to-new-socket-lib
This commit is contained in:
@@ -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()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ namespace ElectronNET.API
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
|
||||
BridgeConnector.Emit("createBrowserWindow", JObject.FromObject(options, ownjsonSerializer), loadUrl);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user