From 68f28d4de7340c145b01829aa85de12b9ed6adf4 Mon Sep 17 00:00:00 2001 From: Pranav anilkumar Wani Date: Mon, 28 Oct 2024 10:23:51 +0530 Subject: [PATCH 1/2] added example of loading dotnet dll into nodejs and electronjs --- examples/dotnet-dll-into-nodejs/BUILD_DLL.md | 70 ++++++++++++ .../ElectronJS/README.md | 93 ++++++++++++++++ .../ElectronJS/index.html | 21 ++++ .../dotnet-dll-into-nodejs/ElectronJS/main.js | 38 +++++++ .../ElectronJS/package.json | 18 ++++ .../ElectronJS/renderer.js | 10 ++ .../MyDotNetLibrary/.DS_Store | Bin 0 -> 6148 bytes .../MyDotNetLibrary/Class1.cs | 11 ++ .../MyDotNetLibrary/MyDotNetLibrary.csproj | 9 ++ .../dotnet-dll-into-nodejs/NodeJS/README.md | 18 ++++ .../dotnet-dll-into-nodejs/NodeJS/index.js | 7 ++ .../NodeJS/package.json | 15 +++ examples/dotnet-dll-into-nodejs/README.md | 101 ++++++++++++++++++ 13 files changed, 411 insertions(+) create mode 100644 examples/dotnet-dll-into-nodejs/BUILD_DLL.md create mode 100644 examples/dotnet-dll-into-nodejs/ElectronJS/README.md create mode 100644 examples/dotnet-dll-into-nodejs/ElectronJS/index.html create mode 100644 examples/dotnet-dll-into-nodejs/ElectronJS/main.js create mode 100644 examples/dotnet-dll-into-nodejs/ElectronJS/package.json create mode 100644 examples/dotnet-dll-into-nodejs/ElectronJS/renderer.js create mode 100644 examples/dotnet-dll-into-nodejs/MyDotNetLibrary/.DS_Store create mode 100644 examples/dotnet-dll-into-nodejs/MyDotNetLibrary/Class1.cs create mode 100644 examples/dotnet-dll-into-nodejs/MyDotNetLibrary/MyDotNetLibrary.csproj create mode 100644 examples/dotnet-dll-into-nodejs/NodeJS/README.md create mode 100644 examples/dotnet-dll-into-nodejs/NodeJS/index.js create mode 100644 examples/dotnet-dll-into-nodejs/NodeJS/package.json create mode 100644 examples/dotnet-dll-into-nodejs/README.md diff --git a/examples/dotnet-dll-into-nodejs/BUILD_DLL.md b/examples/dotnet-dll-into-nodejs/BUILD_DLL.md new file mode 100644 index 00000000..82de41f5 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/BUILD_DLL.md @@ -0,0 +1,70 @@ +### Steps to Build a .DLL on macOS Using the .NET CLI + +1. **Install the .NET SDK for macOS**: + - Download and install the [.NET SDK](https://dotnet.microsoft.com/download) for macOS. + - After installation, you can verify it by running: + + ```bash + dotnet --version + ``` + +2. **Create a New Class Library Project**: + - Open the Terminal, navigate to your desired directory, and create a new class library project by running: + + ```bash + dotnet new classlib -o MyDotNetLibrary + ``` + + - This creates a folder named `MyDotNetLibrary` with a basic class library template. + +3. **Edit the Code**: + - Navigate to the project folder and open the generated `Class1.cs` file with your preferred code editor (VS Code, Sublime, etc.): + + ```bash + cd MyDotNetLibrary + ``` + + - Replace the content with your code: + + ```csharp + using System; + using NodeApi.DotNet; + + namespace MyDotNetLibrary + { + public class MyMathClass + { + public int Add(int a, int b) => a + b; + + [JSExport] + public static string SayHello(string name) => $"Hello, {name} from .NET!"; + } + } + ``` + +4. **Build the DLL**: + - Build the project to produce the `.dll` file: + + ```bash + dotnet build + ``` + + - This generates a `.dll` file in the `bin/Debug/net6.0/` directory by default. + +5. **Locate the DLL File**: + - You can find `MyDotNetLibrary.dll` in the `bin/Debug/net6.0/` directory within the project folder. + +6. **Use the DLL in Node.js**: + - With the `.dll` file ready, you can now load and interact with it in a Node.js application using the `node-api-dotnet` package. + +### Example: Loading the DLL in Node.js on macOS + +```javascript +import dotnet from 'node-api-dotnet/net6.0'; + +dotnet.load('path/to/MyDotNetLibrary.dll'); + +const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass; +const instance = new MyMathClass(); +console.log(instance.Add(3, 5)); // Example usage +``` \ No newline at end of file diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/README.md b/examples/dotnet-dll-into-nodejs/ElectronJS/README.md new file mode 100644 index 00000000..21de36a1 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/README.md @@ -0,0 +1,93 @@ +# ElectronJS + +A sample Electron application that demonstrates loading a .NET `.dll` file and interacting with it using the `node-api-dotnet` package. This example allows you to invoke methods from your .NET assembly directly within your Electron app. + +## Project Structure + +``` +ElectronJS +│ ├── main.js # Main process file +│ ├── renderer.js # Renderer process file +│ ├── index.html # Main HTML file +│ ├── MyDotNetLibrary.dll # .NET DLL file to interact with +│ └── package.json # Project configuration file +``` + +## Prerequisites + +1. **Node.js** - Install [Node.js](https://nodejs.org/) (version 14 or higher recommended). +2. **Electron** - Installed via npm. +3. **.NET SDK** - Required to build `.dll` files. Install from [here](https://dotnet.microsoft.com/download). +4. **node-api-dotnet** - Used to load .NET assemblies into Node.js. + +## Getting Started + +1. **Clone the Repository**: + + ```bash + git clone + cd ElectronJS + ``` + +2. **Add Your DLL File**: + + Make sure your `.NET` library, `MyDotNetLibrary.dll`, is in the project root directory (`MyElectronApp/`). + +3. **Install Dependencies**: + + ```bash + npm install + ``` + +## Project Files + +### `main.js` + +Handles the main process of Electron, loads the `.dll` file, and sets up IPC communication with the renderer process to handle `.NET` method calls. + +### `renderer.js` + +Handles interactions from the HTML UI, sends data to the main process, and displays results. + +### `index.html` + +A simple interface to take input, invoke the .NET function, and display the result. + +## Usage + +1. **Start the Application**: + + ```bash + npm start + ``` + +2. **Using the App**: + + - Enter two numbers in the input fields. + - Click **"Add Numbers"**. + - The result of the addition (calculated by the .NET method) will appear below the button. + +## Sample Code + +### Loading the .NET Assembly + +In `main.js`, the `.dll` file is loaded using `node-api-dotnet`: + +```javascript +const dotnet = require('node-api-dotnet/net6.0'); +dotnet.load(path.join(__dirname, 'MyDotNetLibrary.dll')); +``` + +### Calling a .NET Method from the Renderer + +The `renderer.js` file communicates with the main process to call a `.NET` method: + +```javascript +const result = await ipcRenderer.invoke('dotnet-add', a, b); +``` + +## Troubleshooting + +- **Electron Version**: Ensure compatibility between `node-api-dotnet` and your Electron version. +- **Path Issues**: Double-check the path to `MyDotNetLibrary.dll`. +- **DLL Compatibility**: Ensure that the `.dll` was built for the same .NET runtime as specified (e.g., `net6.0`). diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/index.html b/examples/dotnet-dll-into-nodejs/ElectronJS/index.html new file mode 100644 index 00000000..11325e10 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/index.html @@ -0,0 +1,21 @@ + + + + + + Electron .NET Integration + + +

Electron + .NET Integration

+ + +

+ + +

+ +

Result:

+ + + + diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/main.js b/examples/dotnet-dll-into-nodejs/ElectronJS/main.js new file mode 100644 index 00000000..1a3574cb --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/main.js @@ -0,0 +1,38 @@ +const { app, BrowserWindow, ipcMain } = require('electron'); +const path = require('path'); +const dotnet = require('node-api-dotnet/net8.0'); + +// Load the .NET assembly +dotnet.load(path.join(__dirname, '../MyDotNetLibrary/bin/Debug/net8.0/MyDotNetLibrary.dll')); + +function createWindow() { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + preload: path.join(__dirname, 'renderer.js'), // Renderer script + contextIsolation: false, + nodeIntegration: true + } + }); + + mainWindow.loadFile('index.html'); +} + +// Handle a call from renderer to execute .NET code +ipcMain.handle('dotnet-add', async (event, a, b) => { + const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass; + const instance = new MyMathClass(); + return instance.Add(a, b); +}); + +app.whenReady().then(() => { + createWindow(); + app.on('activate', function () { + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit(); +}); diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/package.json b/examples/dotnet-dll-into-nodejs/ElectronJS/package.json new file mode 100644 index 00000000..6e6a6275 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/package.json @@ -0,0 +1,18 @@ +{ + "name": "electronjs", + "version": "1.0.0", + "description": "Sample Electron app with .NET DLL integration", + "main": "main.js", + "scripts": { + "start": "electron ." + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "electron": "^33.0.2" + }, + "dependencies": { + "node-api-dotnet": "^0.8.16" + } +} diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/renderer.js b/examples/dotnet-dll-into-nodejs/ElectronJS/renderer.js new file mode 100644 index 00000000..1f58b424 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/renderer.js @@ -0,0 +1,10 @@ +const { ipcRenderer } = require('electron'); + +document.getElementById('addButton').addEventListener('click', async () => { + const a = parseInt(document.getElementById('inputA').value); + const b = parseInt(document.getElementById('inputB').value); + + // Call .NET Add method via main process + const result = await ipcRenderer.invoke('dotnet-add', a, b); + document.getElementById('result').innerText = `Result: ${result}`; +}); diff --git a/examples/dotnet-dll-into-nodejs/MyDotNetLibrary/.DS_Store b/examples/dotnet-dll-into-nodejs/MyDotNetLibrary/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6b8d130027f3c0e34bc4341b5534f8cae384a9bc GIT binary patch literal 6148 zcmeHKu};H447F(`BEis+@qVE*%e4wCLh6oCs8m1=*M&V23!ees!Op;E@FhH-U6QmB zBSMue-95)X+sTu1cP1j9KP{(36Cx@w1X+{;5%Zwy$QFx}CC7Aeo9fL#ivMepcOOwj z_w=}4b>IK|xb@VjEUR^@U@7YB&zINL$E@pJ{^H%-b+cX}4D}K!KJ@E7zqg)lz0=FD z+1s{Wj;m8!Z{ORi$5HCJI0MdrGvEw316>AiW{VUjiat97&VV!U!+`7$0YfkvHi~)c zz?546;27pC(507+Wot25!(k7$E*dt98cuA@2V3QB^TN40@`t>f z{06K%`0NbqGB8rZM9%*U{4#@0{%(*zI|I(ZK{3GNa#7ClNp`mGeVm-N0pkWkMAkK; nK%n<70eFyo a + b; + + public static string SayHello(string name) => $"Hello, {name} from .NET!"; + } +} diff --git a/examples/dotnet-dll-into-nodejs/MyDotNetLibrary/MyDotNetLibrary.csproj b/examples/dotnet-dll-into-nodejs/MyDotNetLibrary/MyDotNetLibrary.csproj new file mode 100644 index 00000000..bb23fb7d --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/MyDotNetLibrary/MyDotNetLibrary.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/examples/dotnet-dll-into-nodejs/NodeJS/README.md b/examples/dotnet-dll-into-nodejs/NodeJS/README.md new file mode 100644 index 00000000..7b2d3413 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/NodeJS/README.md @@ -0,0 +1,18 @@ +# dotnet-dll-into-nodejs + +## Pre-requisuite + +1. Install donnet sdk v8 or anyone and try to set that into the `index.js` + +## Usage + +### Step - 1 Install dependencies +```sh +npm i +``` + +### Step - 2 Run the app + +```sh +node . +``` diff --git a/examples/dotnet-dll-into-nodejs/NodeJS/index.js b/examples/dotnet-dll-into-nodejs/NodeJS/index.js new file mode 100644 index 00000000..122ae0c4 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/NodeJS/index.js @@ -0,0 +1,7 @@ +const dotnet = require("node-api-dotnet/net8.0"); +const path = require("path"); +dotnet.load(path.join(__dirname, "../MyDotNetLibrary/bin/Debug/net8.0/MyDotNetLibrary.dll")); + +const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass; +const instance = new MyMathClass(); +console.log(instance.Add(3, 5)); // Example usage diff --git a/examples/dotnet-dll-into-nodejs/NodeJS/package.json b/examples/dotnet-dll-into-nodejs/NodeJS/package.json new file mode 100644 index 00000000..5b7934cc --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/NodeJS/package.json @@ -0,0 +1,15 @@ +{ + "name": "mydotnetlibrary", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "node-api-dotnet": "^0.8.16" + } +} diff --git a/examples/dotnet-dll-into-nodejs/README.md b/examples/dotnet-dll-into-nodejs/README.md new file mode 100644 index 00000000..60a58474 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/README.md @@ -0,0 +1,101 @@ +# DotNet DLL Loader into Node.js and Electron.js + +This repository demonstrates how to load and use a .NET DLL in both Node.js and Electron.js applications. It includes sample code for each environment, making it easy for developers to understand and implement the functionality. + +## Table of Contents + +- [Project Structure](#project-structure) +- [Prerequisites](#prerequisites) +- [Usage](#usage) + - [Node.js Example](#nodejs-example) + - [Electron.js Example](#electronjs-example) +- [Building the .NET Library](#building-the-net-library) + +## Project Structure + +```sh +. +├── ElectronJS +│ ├── README.md # Electron specific instructions +│ ├── index.html # HTML file for the Electron app +│ ├── main.js # Main process for Electron +│ ├── package-lock.json # npm package lock file +│ └── package.json # npm dependencies for Electron +├── LICENSE # License information +├── MyDotNetLibrary # .NET library project +│ ├── Class1.cs # Example .NET class +│ ├── MyDotNetLibrary.csproj # Project file for .NET library +│ ├── bin # Compiled .NET binaries +│ └── obj # Intermediate build files +├── NodeJS # Node.js example +│ ├── README.md # Node.js specific instructions +│ ├── index.js # Main entry point for Node.js +│ ├── package-lock.json # npm package lock file +│ └── package.json # npm dependencies for Node.js +└── dotnet-dll-into-nodejs.sln # Solution file for the project +``` + +## Prerequisites + +To run the examples, you need the following installed on your machine: + +- [.NET SDK (version 8.0 or higher)](https://dotnet.microsoft.com/download) +- [Node.js (version 14 or higher)](https://nodejs.org/) +- [Electron](https://www.electronjs.org/docs/latest/tutorial/quick-start) + +## Usage + +### Node.js Example + +1. Navigate to the `NodeJS` directory: + + ```bash + cd NodeJS + ``` + +2. Install dependencies: + + ```bash + npm install + ``` + +3. Run the Node.js application: + + ```bash + node index.js + ``` + +The `index.js` file demonstrates how to load the .NET DLL and call methods from it. + +### Electron.js Example + +1. Navigate to the `ElectronJS` directory: + + ```bash + cd ElectronJS + ``` + +2. Install dependencies: + + ```bash + npm install + ``` + +3. Run the Electron application: + + ```bash + npm start + ``` + +The Electron app will load the .NET DLL and allow you to interact with it through a user interface defined in `index.html`. + +## Building the .NET Library + +To build the .NET library, navigate to the `MyDotNetLibrary` directory and use the following command: + +```bash +cd MyDotNetLibrary +dotnet build +``` + +This will compile the .NET library and place the output DLL in the `bin/Debug/net8.0` directory. From dca85ac381639cd2f37616c93df51c7679de5dd5 Mon Sep 17 00:00:00 2001 From: Pranav anilkumar Wani Date: Mon, 28 Oct 2024 11:12:17 +0530 Subject: [PATCH 2/2] disabled node_integration --- .../ElectronJS/index.html | 44 +++++++++----- .../dotnet-dll-into-nodejs/ElectronJS/main.js | 57 ++++++++++++------- .../ElectronJS/preload.js | 6 ++ 3 files changed, 74 insertions(+), 33 deletions(-) create mode 100644 examples/dotnet-dll-into-nodejs/ElectronJS/preload.js diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/index.html b/examples/dotnet-dll-into-nodejs/ElectronJS/index.html index 11325e10..21205daf 100644 --- a/examples/dotnet-dll-into-nodejs/ElectronJS/index.html +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/index.html @@ -1,21 +1,39 @@ - - - Electron .NET Integration + + + Electron + .NET Example + -

Electron + .NET Integration

- - -

- - -

- -

Result:

+

Call .NET Method from Electron

+ + + +

- + diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/main.js b/examples/dotnet-dll-into-nodejs/ElectronJS/main.js index 1a3574cb..4d7c8cac 100644 --- a/examples/dotnet-dll-into-nodejs/ElectronJS/main.js +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/main.js @@ -1,38 +1,55 @@ const { app, BrowserWindow, ipcMain } = require('electron'); const path = require('path'); -const dotnet = require('node-api-dotnet/net8.0'); +const dotnet = require('node-api-dotnet/net8.0'); // Adjust according to your target framework -// Load the .NET assembly -dotnet.load(path.join(__dirname, '../MyDotNetLibrary/bin/Debug/net8.0/MyDotNetLibrary.dll')); +let mainWindow; function createWindow() { - const mainWindow = new BrowserWindow({ + mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { - preload: path.join(__dirname, 'renderer.js'), // Renderer script - contextIsolation: false, - nodeIntegration: true - } + contextIsolation: true, // Protect from context isolation + enableRemoteModule: false, + preload: path.join(__dirname, 'preload.js'), // Preload script + }, }); mainWindow.loadFile('index.html'); + + // Open the DevTools (optional) + // mainWindow.webContents.openDevTools(); } -// Handle a call from renderer to execute .NET code -ipcMain.handle('dotnet-add', async (event, a, b) => { - const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass; - const instance = new MyMathClass(); - return instance.Add(a, b); +// IPC to load the .dll and call a method +ipcMain.handle('call-dotnet', async (event, methodName, ...args) => { + try { + // Load the .dll + dotnet.load(path.join(__dirname, '../MyDotNetLibrary/bin/Debug/net8.0/MyDotNetLibrary.dll')); + + // Access the class and method + const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass; + const instance = new MyMathClass(); + + // Call the method dynamically + const result = await instance[methodName](...args); + return result; + } catch (error) { + console.error('Error calling .NET method:', error); + throw error; + } }); -app.whenReady().then(() => { - createWindow(); - app.on('activate', function () { - if (BrowserWindow.getAllWindows().length === 0) createWindow(); - }); +app.whenReady().then(createWindow); + +app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit(); + } }); -app.on('window-all-closed', function () { - if (process.platform !== 'darwin') app.quit(); +app.on('activate', () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow(); + } }); diff --git a/examples/dotnet-dll-into-nodejs/ElectronJS/preload.js b/examples/dotnet-dll-into-nodejs/ElectronJS/preload.js new file mode 100644 index 00000000..56354318 --- /dev/null +++ b/examples/dotnet-dll-into-nodejs/ElectronJS/preload.js @@ -0,0 +1,6 @@ +const { contextBridge, ipcRenderer } = require('electron'); + +// Expose the callDotNet method to the renderer process +contextBridge.exposeInMainWorld('myAPI', { + callDotNet: (methodName, ...args) => ipcRenderer.invoke('call-dotnet', methodName, ...args), +});