node-ffi char**
node-ffiを使って、JavaScriptからC++ DLL内で作成したchar*にアクセスする方法です。
- Win7 64bit
- Visual Studio Community 2013
- node.js@0.12.3
- node-ffi@1.3.1
- ref@1.0.2
C++でバッファを確保して、JavaScriptで受け取ります。JavaScriptで利用するとか、別のC++関数に渡すとかできます。バッファの確保をJavaScript内で行うという方法も考えられますが、char**の扱いが必要な場面での書き方の練習です。
app.ts
var ref = require('ref'); var ffi = require('ffi'); var mylib = ffi.Library('sub', { 'fnsub_create': ['size_t', ['char**']] }); var dataPtrPtr =ref.alloc('char*'); var len = mylib.fnsub_create(dataPtrPtr); var dataPtr = ref.deref(dataPtrPtr); var buf = ref.reinterpret(dataPtr, len, 0); console.log('len =', len); console.log('dataPtrPtr=', dataPtrPtr); console.log('dataPtr =', dataPtr); console.log('buf =', buf); console.log(' (ascii)=', buf.toString('ascii')); console.log(' (value)=', buf[0], buf[1], buf[2], buf[3], buf[4]);
ちなみに、'char**'や'char*'は、'pointer'と書いても問題ないようです。
'fnsub_create': ['size_t', ['pointer']]
var dataPtrPtr =ref.alloc('pointer');
sub.h
#ifdef SUB_EXPORTS #define SUB_API __declspec(dllexport) #else #define SUB_API __declspec(dllimport) #endif extern "C"{ SUB_API size_t fnsub_create(char** dataPtrPtr); }
sub.cpp
#include "stdafx.h" #include <iostream> #include <iomanip> #include "sub.h" SUB_API size_t fnsub_create(char ** dataPtrPtr) { setlocale(LC_ALL, "japanese"); char* dataPtr =*dataPtrPtr =new char[5]; dataPtr[0] ='a'; dataPtr[1] ='b'; dataPtr[2] ='c'; dataPtr[3] ='d'; dataPtr[4] ='\0'; std::cout << "dataPtrPtr:" << std::hex << std::setfill('0') << std::setw(16) << dataPtrPtr << std::endl; std::cout << "dataPtr :" << std::hex << std::setfill('0') << std::setw(16) << (ULONGLONG)dataPtr << std::endl; return 5; }
実行結果
dataPtrPtr:0000000001F81D10 dataPtr :000000000204e9e0 len = 5 dataPtrPtr= <Buffer@0x0000000001F81D10 e0 e9 04 02 00 00 00 00> dataPtr = <Buffer@0x000000000204E9E0 61> buf = <Buffer@0x000000000204E9E0 61 62 63 64 00> (ascii)= abcd (value)= 97 98 99 100 0
1,2行目はC++内でアドレスを印字したもの。
4,5行目はJavaScript内でアドレスを確認してます。
6行目はアドレス('pointer'タイプ)をNode.jsのBufferとして解釈したもの。
var buf = ref.reinterpret(dataPtr, len, 0);
JavaScriptでBuffer確保
JavaScript内でBufferを確保して、C++に引き渡すのはずっと簡単です。
var mylib = ffi.Library('sub', { 'fnsub': ['size_t', ['char*']] }); var buf =new Buffer(5); var len = mylib.fnsub(buf);
C++側は次のような宣言です。dataPtrは普通のバッファとして使えます。
SUB_API size_t fnsub(char * dataPtr);