Native Code and Electron: C++ (Windows)
This tutorial builds on the general introduction to Native Code and Electron and focuses on creating a native addon for Windows using C++ and the Win32 API. To illustrate how you can embed native Win32 code in your Electron app, we'll be building a basic native Windows GUI (using the Windows Common Controls) that communicates with Electron's JavaScript.
Specifically, we'll be integrating with two commonly used native Windows libraries:
comctl32.lib, which contains common controls and user interface components. It provides various UI elements like buttons, scrollbars, toolbars, status bars, progress bars, and tree views. As far as GUI development on Windows goes, this library is very low-level and basic - more modern frameworks like WinUI or WPF are more advanced alternatives but require a lot more C++ and Windows version considerations than are useful for this tutorial. This way, we can avoid the many perils of building native interfaces for multiple Windows versions!shcore.lib, a library that provides high-DPI awareness functionality and other Shell-related features around managing displays and UI elements.
This tutorial will be most useful to those who already have some familiarity with native C++ GUI development on Windows. You should have experience with basic window classes and procedures, like WNDCLASSEXW and WindowProc functions. You should also be familiar with the Windows message loop, which is the heart of any native application - our code will be using GetMessage, TranslateMessage, and DispatchMessage to handle messages. Lastly, we'll be using (but not explaining) standard Win32 controls like WC_EDITW or WC_BUTTONW.
If you're not familiar with C++ GUI development on Windows, we recommend Microsoft's excellent documentation and guides, particularly for beginners. "Get Started with Win32 and C++" is a great introduction.
Requirements
Just like our general introduction to Native Code and Electron, this tutorial assumes you have Node.js and npm installed, as well as the basic tools necessary for compiling native code. Since this tutorial discusses writing native code that interacts with Windows, we recommend that you follow this tutorial on Windows with both Visual Studio and the "Desktop development with C++ workload" installed. For details, see the Visual Studio Installation instructions.
1) Creating a package
You can re-use the package we created in our Native Code and Electron tutorial. This tutorial will not be repeating the steps described there. Let's first setup our basic addon folder structure:
my-native-win32-addon/
├── binding.gyp
├── include/
│ └── cpp_code.h
├── js/
│ └── index.js
├── package.json
└── src/
├── cpp_addon.cc
└── cpp_code.cc
Our package.json should look like this:
{
"name": "cpp-win32",
"version": "1.0.0",
"description": "A demo module that exposes C++ code to Electron",
"main": "js/index.js",
"author": "Your Name",
"scripts": {
"clean": "rm -rf build_swift && rm -rf build",
"build-electron": "electron-rebuild",
"build": "node-gyp configure && node-gyp build"
},
"license": "MIT",
"dependencies": {
"bindings": "^1.5.0",
"node-addon-api": "^8.3.0"
}
}
2) Setting Up the Build Configuration
For a Windows-specific addon, we need to modify our binding.gyp file to include Windows libraries and set appropriate compiler flags. In short, we need to do the following three things:
- We need to ensure our addon is only compiled on Windows, since we'll be writing platform-specific code.
- We need to include the Windows-specific libraries. In our tutorial, we'll be targeting
comctl32.libandshcore.lib. - We need to configure the compiler and define C++ macros.
{
"targets": [
{
"target_name": "cpp_addon",
"conditions": [
['OS=="win"', {
"sources": [
"src/cpp_addon.cc",
"src/cpp_code.cc"
],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")",
"include"
],
"libraries": [
"comctl32.lib",
"shcore.lib"
],
"dependencies": [
"<!(node -p \"require('node-addon-api').gyp\")"
],
"msvs_settings": {
"VCCLCompilerTool": {
"ExceptionHandling": 1,
"DebugInformationFormat"