Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Nan to Napi #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
17 changes: 7 additions & 10 deletions binding.gyp
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
{
"targets": [{
"target_name": "binding",
"cflags!": [ "-fno-exceptions" ], # 忽略编译时异常
"cflags_cc!": [ "-fno-exceptions" ], # 忽略编译时异常
"sources": [
"src/main.cc"
],
"include_dirs": ["<!(node -e \"require('nan')\")"],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
"conditions": [
['OS=="mac"',
{
Expand Down Expand Up @@ -38,21 +42,14 @@
"src/clip_win.cc"
],
'defines': [
'__WIN32__'
'__WIN32__',
'NAPI_DISABLE_CPP_EXCEPTIONS' # 禁用 N-API 中的 C++ 异常处理机制, N-API 函数在发生错误时会返回一个错误码,而不是抛出异常
]
}
],
['OS=="linux"',
{}
]
]
}, {
"target_name": "action_after_build",
"type": "none",
"dependencies": ["<(module_name)"],
"copies": [{
"files": [ "<(PRODUCT_DIR)/<(module_name).node" ],
"destination": "<(module_path)"
}]
}]
}
5 changes: 1 addition & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
var binary = require('@mapbox/node-pre-gyp');
var path = require('path');
var binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')));
var binding = require(binding_path);
const binding = require('bindings')('binding')
module.exports = exports = binding;
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clipboard-files",
"version": "2.0.0",
"version": "2.0.1",
"description": "A nodejs addon, read or write file paths for clipboard, supports win32 and mac osx",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
Expand All @@ -26,14 +26,13 @@
"url": "https://github.com/alex8088/clipboard-files.git"
},
"scripts": {
"test": "node ./test",
"install": "node-pre-gyp install --fallback-to-build"
"test": "node test"
},
"author": "alex.wei",
"author": "bubuzi",
"license": "MIT",
"gypfile": true,
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.10",
"nan": "^2.17.0"
"bindings": "~1.2.1",
"node-addon-api": "^1.0.0"
}
}
140 changes: 87 additions & 53 deletions src/clip_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,55 @@

char *GBK2Utf8(const char *strGBK)
{
WCHAR *str1;
int n = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
str1 = new WCHAR[n];
MultiByteToWideChar(CP_ACP, 0, strGBK, -1, str1, n);
n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
char *str2 = new char[n];
WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
delete[] str1;
str1 = NULL;
return str2;
WCHAR *str1;
int n = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
str1 = new WCHAR[n];
MultiByteToWideChar(CP_ACP, 0, strGBK, -1, str1, n);
n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
char *str2 = new char[n];
WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
delete[] str1;
str1 = NULL;
return str2;
}

Local<Array> get_file_names(Isolate *isolate)
Napi::Value get_file_names(const Napi::CallbackInfo &info)
{
Local<Array> fileNames = Array::New(isolate, 0);
Local<Context> context = isolate->GetCurrentContext();
if (OpenClipboard(NULL)) // open clipboard
{
HDROP hDrop = HDROP(::GetClipboardData(CF_HDROP)); // get the file path hwnd of clipboard
if (hDrop != NULL)
{
char szFilePathName[MAX_PATH + 1] = { 0 };
UINT nNumOfFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // get the count of files
fileNames = Array::New(isolate, nNumOfFiles);
for (UINT nIndex = 0; nIndex < nNumOfFiles; ++nIndex)
{
memset(szFilePathName, 0, MAX_PATH + 1);
DragQueryFile(hDrop, nIndex, szFilePathName, MAX_PATH); // get file name
fileNames->Set(context, nIndex, String::NewFromUtf8(isolate, GBK2Utf8(szFilePathName), NewStringType::kNormal).ToLocalChecked());
}
}
CloseClipboard(); // close clipboard
}
return fileNames;

Napi::Env env = info.Env();
// uint32_t index = 0;

Napi::Array fileNames;
if (OpenClipboard(NULL)) // open clipboard
{
HDROP hDrop = HDROP(::GetClipboardData(CF_HDROP)); // get the file path hwnd of clipboard
if (hDrop != NULL)
{
char szFilePathName[MAX_PATH + 1] = {0};

UINT nNumOfFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // get the count of files
fileNames = Napi::Array::New(env, nNumOfFiles);
for (UINT nIndex = 0; nIndex < nNumOfFiles; ++nIndex)
{
memset(szFilePathName, 0, MAX_PATH + 1);

DragQueryFile(hDrop, nIndex, (LPSTR)szFilePathName, MAX_PATH); // get file name
fileNames.Set(nIndex, Napi::String::New(env, GBK2Utf8(szFilePathName)));
}
}
CloseClipboard(); // close clipboard
}
return fileNames;
}

std::wstring stringToWstring(const std::string& str)
std::wstring stringToWstring(const std::string &str)
{
int nLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
if (nLen == 0)
if (nLen == 0)
return std::wstring(L"");

wchar_t* wide = new wchar_t[nLen];
if (!wide)
wchar_t *wide = new wchar_t[nLen];
if (!wide)
return std::wstring(L"");

MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wide, nLen);
Expand All @@ -55,17 +60,43 @@ std::wstring stringToWstring(const std::string& str)
return wstr;
}

void write_file_names(Isolate *isolate, Local<Array> fileNames)
Napi::Value write_file_names(const Napi::CallbackInfo &info)
{
Local<Context> context = isolate->GetCurrentContext();

Napi::Env env = info.Env();
if (info.Length() != 1)
{
Napi::Error::New(env, "Expected exactly one argument")
.ThrowAsJavaScriptException();
return env.Undefined();
}
if (!(info[0].IsArray() || info[0].IsString()))
{
Napi::Error::New(env, "Expect a string or array of strings")
.ThrowAsJavaScriptException();
return env.Undefined();
}
std::vector<wstring> files;
for (size_t i = 0; i < fileNames->Length(); i++) {
MaybeLocal<Value> maybeIndex = fileNames->Get(context, i);
Local<Value> index = maybeIndex.ToLocalChecked();
String::Utf8Value path(isolate, index);
std::string pathStr(*path);
files.push_back(stringToWstring(pathStr));
if (info[0].IsArray())
{
Napi::Array fileNames = info[0].As<Napi::Array>();

for (size_t i = 0; i < fileNames.Length(); i++)
{
Napi::Value item = fileNames.Get(i);
if (!item.IsString())
{
Napi::Error::New(env, "Expect a string or array of strings")
.ThrowAsJavaScriptException();
return info.Env().Undefined();
}
std::string filename = item.ToString();
files.push_back(stringToWstring(filename));
}
}
else
{
std::string filename = info[0].As<Napi::String>();
files.push_back(stringToWstring(filename));
}

size_t bytes = sizeof(DROPFILES);
Expand All @@ -74,23 +105,26 @@ void write_file_names(Isolate *isolate, Local<Array> fileNames)
bytes += sizeof(wchar_t);
HANDLE hdata = ::GlobalAlloc(GMEM_MOVEABLE, bytes);
if (!hdata)
return;
DROPFILES* drop_files = static_cast<DROPFILES*>(::GlobalLock(hdata));
return env.Undefined();
DROPFILES *drop_files = static_cast<DROPFILES *>(::GlobalLock(hdata));
drop_files->pFiles = sizeof(DROPFILES);
drop_files->fWide = TRUE;
BYTE* data = reinterpret_cast<BYTE*>(drop_files) + sizeof(DROPFILES);
BYTE *data = reinterpret_cast<BYTE *>(drop_files) + sizeof(DROPFILES);
// Copy the strings stored in 'files' with proper NULL separation.
wchar_t* data_pos = reinterpret_cast<wchar_t*>(data);
for (size_t i = 0; i < files.size(); ++i) {
wchar_t *data_pos = reinterpret_cast<wchar_t *>(data);
for (size_t i = 0; i < files.size(); ++i)
{
size_t offset = files[i].length() + 1;
memcpy(data_pos, files[i].c_str(), offset * sizeof(wchar_t));
data_pos += offset;
}
data_pos[0] = L'\0'; // Double NULL termination after the last string.
}
data_pos[0] = L'\0'; // Double NULL termination after the last string.
::GlobalUnlock(hdata);
if (OpenClipboard(NULL)) {
if (OpenClipboard(NULL))
{
EmptyClipboard();
SetClipboardData(CF_HDROP, hdata);
CloseClipboard();
}
}
return env.Undefined();
}
16 changes: 3 additions & 13 deletions src/clip_win.h
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
#include <windows.h>
#include <node.h>
#include <napi.h>
#include <shlobj.h>
#include <vector>
#include <string>
#include <iostream>

using namespace std;
using v8::Context;
using v8::Array;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::String;
using v8::NewStringType;
using v8::Value;

Local<Array> get_file_names(Isolate *isolate);
Napi::Value get_file_names(const Napi::CallbackInfo &info);

void write_file_names(Isolate *isolate, Local<Array> fileNames);
Napi::Value write_file_names(const Napi::CallbackInfo &info);
53 changes: 18 additions & 35 deletions src/main.cc
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
#include <node.h>
#include <napi.h>
#ifdef __WIN32__
#include "clip_win.h"
#elif __APPLE__
#include "clip_osx.h"
#endif

namespace clipboard
{
using v8::Context;
using v8::Array;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::String;
using v8::NewStringType;
using v8::Value;

void readFiles(const FunctionCallbackInfo<Value> &args)
{
Isolate *isolate = args.GetIsolate();
Local<Array> fileNames = get_file_names(isolate);
args.GetReturnValue().Set(fileNames);
}
Napi::Value get_file_names(const Napi::CallbackInfo &info);

void writeFiles(const FunctionCallbackInfo<Value> &args)
{
if (args[0]->IsArray()) {
Isolate *isolate = args.GetIsolate();
Local<Array> array = Local<Array>::Cast(args[0]);
write_file_names(isolate, array);
}
}
Napi::Value write_file_names(const Napi::CallbackInfo &info);

void Init(Local<Object> exports)
{
NODE_SET_METHOD(exports, "readFiles", readFiles);
NODE_SET_METHOD(exports, "writeFiles", writeFiles);
}
static Napi::Value readFiles(const Napi::CallbackInfo &info)
{
return get_file_names(info);
}
static Napi::Value writeFiles(const Napi::CallbackInfo &info)
{
return write_file_names(info);
}
static Napi::Object Init(Napi::Env env, Napi::Object exports)
{
exports["readFiles"] = Napi::Function::New(env, readFiles);
exports["writeFiles"] = Napi::Function::New(env, writeFiles);
return exports;
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
5 changes: 3 additions & 2 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const clipboard = require("../lib");
const { join } = require('path')
const clipboard = require(`../lib`)
if (process.platform === 'darwin') {
clipboard.writeFiles(['/Users/Alex/Download/helloWorld.js']); // rewrite an existing path
} else if (process.platform === 'win32') {
clipboard.writeFiles(['C:\\Users\\Alex\\Documents\\helloWorld.js']); // rewrite an existing path
clipboard.writeFiles(join(__dirname, "helloWorld.js")); // rewrite an existing path
}
console.log("files:", clipboard.readFiles());