Skip to content

Instantly share code, notes, and snippets.

@tatsuyasusukida
Last active June 13, 2022 22:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tatsuyasusukida/f502ba76cffa21610e109ba11e729804 to your computer and use it in GitHub Desktop.
Save tatsuyasusukida/f502ba76cffa21610e109ba11e729804 to your computer and use it in GitHub Desktop.
⚡️ How to call a C language program from Electron using stdio [video version available]

⚡️ How to call a C language program from Electron using stdio [video version available]

Video version thumbnail: How to call a C language program from Electron using stdio

About this article

This article describes how to call a C language program from Electron using standard input/output. When calling a C language program, the spawn function included in the child_process, which is the standard library of Node.js, is called from the main process. The related resources are shown below.

Procedure

The procedure is shown below.

  1. C language coding preparation
  2. C language coding
  3. C language build
  4. Electron coding preparation
  5. Electron coding
  6. Operation check

C language coding preparation

Run the following commands in your terminal to prepare for C language coding

mkdir electron-child-process
cd electron-child-process
touch add.c

C language coding

add.c

Open add.c in your editor and enter the following content.

Click to go to add.c

C language build

Run the following command in your terminal to build the C language source code.

gcc -o add add.c

Electron coding preparation

Run the following commands in your terminal to prepare for Electron coding.

npm init -y
npm install --save-dev electron
touch index.html main.js

Electron coding

index.html

Open index.html in your editor and enter the following content.

Click to go to index.html

main.js

Open main.js in your editor and enter the following content.

Click to go to main.js

The points are shown below.

  1. Since it is necessary to wait for the exit of the child process, enclose the entire processing related to the spawn function in Promise.
  2. Call the spawn function to start the child process.
  3. Pipe the standard error output of the child process to the standard error output of the main process so that you can see the error messages when they are written to the standard error output of the child process.
  4. Add an event handler to the data event of the child process's standard output to get the output.
  5. Add an event handler in the exit event of the child process and wait for the exit. When the child process exits, the event handler is called with the exit code as an argument, so check that the exit code is 0 before resolving the promise.
  6. Add an event handler in the error event of the child process and reject the promise when a start error or execution error occurs.

package.json

Open package.json in your editor and change the main property as follows.

  "main": "main.js",

Operation check

Run the following command to start Electron.

npx electron .

Check that the execution result is the same as the following.

{"sum":"3"}

Conclusion

I don't have enough knowledge, but I think it would be difficult to create a Node.js native module in C and call it from Electron. On the other hand, standard I / O is easy to use, so I use this method. One of the advantages of this method is that it is easy to debug because the C language program can be started by itself. You can also replace the C language program later. On the other hand, one of the disadvantages is that there is an overhead in starting the child process, which reduces performance. In cases where you need to call handreds of times per second, it may be better to create a native module. If you have any opinions or impressions, please feel free to comment. Thank you for reading!

Related article

/node_modules/
/add
/package-lock.json
# Do not ignore package-lock.json other than gist.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv) {
long a;
long b;
if (argc <= 2) {
fprintf(stderr, "argc <= 2\n");
return 1;
}
a = strtol(argv[1], NULL, 10);
b = strtol(argv[2], NULL, 10);
printf("%ld", a + b);
return 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
<title>How to call a C language program from Electron using stdio</title>
</head>
<body>
<h1>How to call a C language program from Electron using stdio</h1>
<p>Check that {"sum": "3"} is output to the terminal.</p>
</body>
</html>
const {app, BrowserWindow} = require('electron')
const path = require('path')
const {spawn} = require('child_process')
async function createWindow () {
try {
const sum = await new Promise((resolve, reject) => { // <1>
const command = path.join(__dirname, 'add')
const args = ['1', '2']
const add = spawn(command, args) // <2>
const chunks = []
add.stderr.pipe(process.stderr) // <3>
add.stdout.on('data', chunk => chunks.push(chunk)) // <4>
add.once('exit', (code) => { // <5>
if (code !== 0) {
reject(new Error('code !== 0'))
} else {
resolve(Buffer.concat(chunks).toString())
}
})
add.once('error', err => reject(err)) // <6>
})
console.info(JSON.stringify({sum}))
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
})
mainWindow.loadFile('index.html')
} catch (err) {
console.error(err)
app.quit()
}
}
app.whenReady().then(() => {
createWindow()
})
app.on('window-all-closed', function () {
app.quit()
})
{
"name": "electron-child-process",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"build": "gcc -o add add.c",
"dev": "electron ."
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"electron": "^18.2.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment