node-ffi char**

node-ffiを使って、JavaScriptからC++ DLL内で作成したchar*にアクセスする方法です。

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);