Skip to content
Open
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
5 changes: 4 additions & 1 deletion docs/Core/Migration-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dotnet add package ElectronNET.Core.AspNet # For ASP.NET projects
### Step 2: Configure Project Settings

**Auto-generated Configuration:**
ElectronNET.Core automatically creates `electron-builder.json` during the first build or NuGet restore. No manual configuration is needed for basic setups.
ElectronNET.Core automatically creates `electron-builder.json` in the `Properties` folder of your project during the first build or NuGet restore. No manual configuration is needed for basic setups.

**Migrate Existing Configuration:**
If you have an existing `electron.manifest.json` file:
Expand Down Expand Up @@ -63,6 +63,9 @@ You can also manually edit `electron-builder.json`:
}
```

**Modify Launch Settings:**
ElectronNET.Core no longer needs a separate CLI tool (electronize.exe) for launching. You should update your launch settings to use either the ASP.NET-first or Electron-first approach. See [Debugging](../Using/Debugging.md) for details.

## 🎯 Testing Migration

After completing the migration steps:
Expand Down
106 changes: 106 additions & 0 deletions src/ElectronNET.API/API/IpcMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,29 @@ public void OnSync(string channel, Func<object, object> listener)
});
}

/// <summary>
/// Send a message to the renderer process synchronously via channel,
/// you can also send arbitrary arguments.
///
/// Note: Sending a synchronous message will block the whole renderer process,
/// unless you know what you are doing you should never use it.
/// </summary>
/// <param name="channel"></param>
/// <param name="listener"></param>
public void OnSync(string channel, Func<object, Task<object>> listener)
{
BridgeConnector.Socket.Emit("registerSyncIpcMainChannel", channel);
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
Task.Run(async () =>
{
var arg = FormatArguments(args);
var result = await listener(arg);
BridgeConnector.Socket.Emit(channel + "Sync", result);
});
});
}

/// <summary>
/// Adds a one time listener method for the event. This listener is invoked only
/// the next time a message is sent to channel, after which it is removed.
Expand Down Expand Up @@ -154,5 +177,88 @@ public void Send(BrowserView browserView, string channel, params object[] data)
{
BridgeConnector.Socket.Emit("sendToIpcRendererBrowserView", browserView.Id, channel, data);
}

/// <summary>
/// Adds a handler for an invokeable IPC. This handler will be called
/// whenever a renderer calls ipcRenderer.invoke(channel, ...args).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void Handle(string channel, Func<object, object> listener)
{
BridgeConnector.Socket.Emit("registerHandleIpcMainChannel", channel);
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
var arg = FormatArguments(args);
var result = listener(arg);
BridgeConnector.Socket.Emit(channel + "Handle", result);
});
}

/// <summary>
/// Adds a handler for an invokeable IPC. This handler will be called
/// whenever a renderer calls ipcRenderer.invoke(channel, ...args).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void Handle(string channel, Func<object, Task<object>> listener)
{
BridgeConnector.Socket.Emit("registerHandleIpcMainChannel", channel);
BridgeConnector.Socket.On<JsonElement>(channel, (args) =>
{
Task.Run(async () =>
{
var arg = FormatArguments(args);
var result = await listener(arg);
BridgeConnector.Socket.Emit(channel + "Handle", result);
});
});
}

/// <summary>
/// Handles a single invokeable IPC message, then removes the listener.
/// See ipcMain.handle(channel, listener).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void HandleOnce(string channel, Func<object, object> listener)
{
BridgeConnector.Socket.Emit("registerHandleOnceIpcMainChannel", channel);
BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>
{
var arg = FormatArguments(args);
var result = listener(arg);
BridgeConnector.Socket.Emit(channel + "HandleOnce", result);
});
}

/// <summary>
/// Handles a single invokeable IPC message, then removes the listener.
/// See ipcMain.handle(channel, listener).
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void HandleOnce(string channel, Func<object, Task<object>> listener)
{
BridgeConnector.Socket.Emit("registerHandleOnceIpcMainChannel", channel);
BridgeConnector.Socket.Once<JsonElement>(channel, (args) =>
{
Task.Run(async () =>
{
var arg = FormatArguments(args);
var result = await listener(arg);
BridgeConnector.Socket.Emit(channel + "HandleOnce", result);
});
});
}

/// <summary>
/// Removes any handler for channel, if present.
/// </summary>
/// <param name="channel">Channelname.</param>
public void RemoveHandler(string channel)
{
BridgeConnector.Socket.Emit("removeHandlerIpcMainChannel", channel);
}
}
}
25 changes: 25 additions & 0 deletions src/ElectronNET.Host/api/ipc.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/ElectronNET.Host/api/ipc.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions src/ElectronNET.Host/api/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,34 @@ export = (socket: Socket) => {
}
});

socket.on('registerHandleIpcMainChannel', (channel) => {
ipcMain.handle(channel, (event, args) => {
return new Promise((resolve, _reject) => {
socket.removeAllListeners(channel + 'Handle');
socket.on(channel + 'Handle', (result) => {
resolve(result);
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
});

socket.on('registerHandleOnceIpcMainChannel', (channel) => {
ipcMain.handleOnce(channel, (event, args) => {
return new Promise((resolve, _reject) => {
socket.removeAllListeners(channel + 'HandleOnce');
socket.once(channel + 'HandleOnce', (result) => {
resolve(result);
});
electronSocket.emit(channel, [event.preventDefault(), args]);
});
});
});

socket.on('removeHandlerIpcMainChannel', (channel) => {
ipcMain.removeHandler(channel);
});

// Integration helpers: programmatically click menu items from renderer tests
ipcMain.on('integration-click-application-menu', (event, id: string) => {
try {
Expand Down