# 🚀node原生插件addon的编写
📅 2023/6/8
🙈由于我本身对c语言及c++语言并不熟悉,因此只能简单的做个入门笔记。
addon插件官方示例 (opens new window)
node-addon-api module (opens new window)
在官方示例中可能会有以下几种不同的代码
- nan:Node 和直接 V8 API 之间基于 C++ 的抽象。
- Node-API:基于 C 的 API,保证跨不同节点版本和 JavaScript 引擎的 ABI 稳定性。 (Node-API 以前称为 N-API。)
- node-addon-api: header-only C++ 包装类,简化了基于 C 的 Node-API 的使用。
- node-addon-api-addon-class:类似于 node-addon-api,但派生自 Napi::Addon 类。 1_hello_world 提供了一个例子。
我使用的为node-addon-api版本,编写了一个可以根据窗口名置顶窗口的addon。
# 安装编译addon所需依赖
npm i node-addon-api bindings
编译同时需要python环境,我目前的环境为python 3.11.1与node 16.20.0 可以正常编译。
# 包含文件
- binding.gyp:是一个用于描述 C++ 扩展的配置文件,它可以让你指定编译器、编译选项、源文件等等。由一个 JSON 对象组成,包含一个或多个 target。每个 target 描述了一个 C++ 扩展。常用的属性:target_name: 扩展的名称。 sources: 扩展的源文件。 include_dirs: 头文件的路径。 libraries: 需要链接的库。 conditions: 条件编译。
- TopWin.cc:用于实现置顶功能的c++文件
- index.js:调用编译好的addon的测试文件。
- package.json
# 文件内容
🗃️binding.gyp
{
"targets": [
{
"target_name": "TopWin",
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"sources": [ "TopWin.cc" ],
"target_arch": "ia32",
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
}
]
}
🗃️TopWin.cc
// node-addon-api
#include <napi.h>
#include <windows.h>
Napi::Boolean TopWin(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int parame_length = info.Length();
std::string title_name = info[0].As<Napi::String>().Utf8Value();
HWND hwnd = FindWindow(NULL, title_name.c_str());
if (parame_length == 2)
{
boolean is_top = info[1].As<Napi::Boolean>();
if (is_top)
{
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
else
{
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
else if (parame_length == 4)
{
boolean is_position = info[3].As<Napi::Boolean>();
if (is_position)
{
int position_x = info[1].As<Napi::Number>().Int32Value();
int position_y = info[2].As<Napi::Number>().Int32Value();
SetWindowPos(hwnd, HWND_TOPMOST, position_x, position_y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
else
{
int width = info[1].As<Napi::Number>().Int32Value();
int height = info[2].As<Napi::Number>().Int32Value();
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
}
}
else if (parame_length == 5)
{
int position_x = info[1].As<Napi::Number>().Int32Value();
int position_y = info[2].As<Napi::Number>().Int32Value();
int width = info[3].As<Napi::Number>().Int32Value();
int height = info[4].As<Napi::Number>().Int32Value();
SetWindowPos(hwnd, HWND_TOPMOST, position_x, position_y, width, height, SWP_NOZORDER);
}
return Napi::Boolean::New(env, true);
}
Napi::Object Init(Napi::Env env, Napi::Object exports)
{
exports.Set(Napi::String::New(env, "TopWin"), Napi::Function::New(env, TopWin));
return exports;
}
NODE_API_MODULE(TopWin, Init)
🗃️package.json
{
//build为编译TopWin.cc的命令
...
"scripts": {
"build": "node-gyp configure && node-gyp build"
},
...
}
🗃️index.js
const top = require('你编译好的.node文件路径')
console.log(top.TopWin('需要置顶程序的窗口名'))
编译好的测试文件点此下载。
该插件的功能大概为:
- 如果传输两个参数(窗口名称,是否置顶)则会置顶窗口与取消窗口置顶。
- 如果传输四个参数(窗口名称,改变位置|改变大小,x坐标|窗口宽度,y坐标|窗口高度)则会修改窗口的位置或大小,第二个参数为true,修改位置,第二个参数为false,否则修改大小。
- 如果传输五个参数(窗口名称,x坐标,y坐标,窗口宽度,窗口高度)则会修改窗口的位置和大小
在Electron中可以直接require相应原生模块使用,如果渲染进程开启了node功能,渲染进程也可以直接调用。