55318

How to use mixed C++ & .Net dll in node.js? (Error: abort() has been called)

Question:

I want to create a native node extension using a dll containing C++ and C# code in Visual Studio 2015. I cannot make it work following <a href="https://stackoverflow.com/q/11257690/709537" rel="nofollow">my own instructions</a> of yesteryear, which is based on the latest node-gyp.

When not using the /clr option, I can run a program like the following just fine.

console.log("1"); const addon = require('./build/Release/addon'); console.log("2");

When enabling /clr, only the first call to log gets executed. When compiling the dll in debug mode, I get the following message:

<a href="https://i.stack.imgur.com/QkqtZ.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/QkqtZ.png" data-original="https://i.stack.imgur.com/QkqtZ.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

How to fix / debug this?

(I know there's edge, but I am trying to go the node-gyp way)

Answer1:

After unsuccessfully twiddling all (?) the compiler and linker options in VS2015, I found out how to set up my binding.gyp instead, in order to get .Net to work:

{ "targets": [ { "target_name": "addon", "sources": [ "hello.cc" ], "msbuild_settings": { "ClCompile": { "CompileAsManaged": "true", "ExceptionHandling": "Async", }, }, } ] }

I verified the build by successfully executing the following mix of managed and unmanaged code:

#include <node.h> #include <v8.h> namespace demo { #pragma managed void callManaged() { System::String^ result = gcnew System::String("hola"); System::Console::WriteLine("It works: " + result); } #pragma unmanaged using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; void Method(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); callManaged(); args.GetReturnValue().Set(String::NewFromUtf8(isolate, "woooooorld")); } void init(Local<Object> exports) { NODE_SET_METHOD(exports, "hello", Method); } NODE_MODULE(addon, init) }

Answer2:

Unless one really must use node-gyp, these days cmake-js and node-addon-api (provides a ABI so you don't need to rebuild for a new Node.js version) should be used. This CMakeLists.txt for <a href="https://www.npmjs.com/package/cmake-js" rel="nofollow">cmake-js</a> compiles mixed native/managed code:

cmake_minimum_required(VERSION 2.8) project (my-addon) set(SOURCE_FILES src/main.cc) add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node" COMMON_LANGUAGE_RUNTIME "") # "pure" and "safe" unsupported in VS 2017 target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/node_modules/node-addon-api PRIVATE ${CMAKE_JS_INC}) target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})

Start with a package.json like

{ "name": "my-addon", "version": "1.0.0", "description": "My node.js addon", "main": "main.js", "scripts": { "test": "node main.js", "install": "cmake-js compile" } }

with a main.js like

var addon = require('bindings')('my-addon'); console.log("hello: " + addon.doSomething());

a src/main.cc like

#include <napi.h> namespace myaddon { #pragma managed void callManaged() { System::String^ result = gcnew System::String("hola"); System::Console::WriteLine("It works: " + result); } #pragma unmanaged Napi::String MyMethod(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); callManaged(); return Napi::String::New(env, "world"); } Napi::Object Init(Napi::Env env, Napi::Object exports) { exports.Set(Napi::String::New(env, "doSomething"), Napi::Function::New(env, MyMethod)); return exports; } NODE_API_MODULE(myaddon, Init) }

To build, run

npm install bindings npm install node-addon-api npm install cmake-js npm install

To execute, run

npm test

Recommend

  • NaN errors with bbmle
  • HTML5 Link to section
  • Nested fragments getchildfragmentmanager causing crash
  • Programming Phoenix: undefined function page_path/2
  • R create adjacency matrix according to columns from data.frame
  • Cython: size attribute of memoryviews
  • Javascript increment operation order of evaluation
  • Qt4: adjust which widget get focused on start
  • Closing a nested stream closes its parent streams too?
  • React Proxy error: Could not proxy request /api/ from localhost:3000 to http://localhost:8000 (ECONN
  • How to create the Iphone application without MAC OS [duplicate]
  • How to implement singleton pattern in android
  • file_get_contents Adding numbers from 2 text files
  • Launch Activity in android via Dialpad using Secret Code
  • Prevent “Too many simultaneous invocations” on formSubmit
  • Why do I get a message saying 1.not.found.as.a.resource?
  • Invalid date [dd/mm/yyyy] in safari? How to display in dd/mm/yyyy format using jquery
  • emacs -nw issues with cscope and terminals
  • Can't resize canvas/scale using Fabric.js
  • spring-data-redis Jackson serialization
  • Python Django ImportError: No module named website
  • summarize data from csv using R
  • Javascript Generated Image Gallery
  • Facebook Comments on your website via Graph API instead of Comments plugin?
  • Appending spaces with str_pad
  • Static analysis of header inclusion in C++
  • Advertising Identifier for devices lower than iOS 6.0
  • WSO2 Identity Server + Rest STS Client (without ESB)
  • How to set http status code when responding to servlet client from Filter class-method in tomcat
  • Keep rows with certain values always at the bottom while sorting in jquery tablesorter plugin
  • How to change the host IP sent in emails to new GitLab users to a publicly visible IP, not the local
  • Cloud Code: Creating a Parse.File from URL
  • Why my AngularJS async test in Jasmine 1.3.x is not working?
  • Capture SIGFPE from SIMD instruction
  • Using Service Component Runtime
  • How do I use TagLib-Sharp to write custom (PRIV) ID3 frames?
  • CAS 4 - Not able to retrieve the LDAP groups after successful authentication