0

我们目前正在尝试将 dll 与 NodeJS 集成。dll 是一个消息总线,它在总线上接收到新消息时触发回调(如果已注册)。附加的 dll 模拟了这种行为:无限循环,并在每个循环中调用带有回调的 C 方法。这是我的测试用例:

var ref = require("ref");
var ffi = require('ffi');
var events = require('events');
var util = require('util');

var voidPtr = ref.types.void;

// Expose the DLL to node JS
var apiLib = ffi.Library('../bin/dispatch', {
    // C method declaring the callback
    'dispatchRegisterCallback': [ 'int', ['pointer', 'int'] ],
    // C method which simply call dispatchRegisterCallback
    'dispatchCallCallback': [ 'int', []]
});

// Callback
var myCallbackPtr = ffi.Callback('void', ['string'], function (message) {
    console.log('callback: ' + message);
});

// Registering the callback on the C method, starts a loop and
// call the method that triggers the callback from the Dll each 1 second
// DOES NOT WORK
apiLib.dispatchRegisterCallback(myCallbackPtr, 1000);

// Make Node Loop
setInterval(function() {
    console.log("loop");
    // Triggering the callback from NodeJS : OK
    //apiLib.dispatchCallCallback();
}
, 100);
// Keep the callback pointer to avoid GC
process.on('exit', function() {
    myCallbackPtr
})

这是示例dll的源代码

#include "stdafx.h"
#include "dispatch.h"
#include <iostream>

pfnCallback * g_pfnCallback = NULL;

void CALLBACK timerFn(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime)
{
       std::cout << "dispatch.dll, timerFn" << std::endl;
       if (g_pfnCallback != NULL)
       {
             std::cout << "dispatch.dll, timerFn : calling callback " << g_pfnCallback << std::endl;
             g_pfnCallback("callback call (timer)");
       }
}

/**
* Register a callback.
*/
int __stdcall dispatchRegisterCallback(pfnCallback fn, int interval)
{
       std::cout << "dispatch.dll, dispatchRegisterCallback" << std::endl;
       g_pfnCallback = fn;
       SetTimer(NULL, 0, interval, (TIMERPROC)timerFn);

       return true;
}

int __stdcall dispatchCallCallback()
{
       std::cout << "dispatch.dll, dispatchCallCallback" << std::endl;
       if (g_pfnCallback != NULL)
       {
             std::cout << "dispatch.dll, dispatchCallCallback : calling callback " << g_pfnCallback << std::endl;
             g_pfnCallback("callback call by dispatchCallCallback");
             return true;
       }
       return false;
}

FFI模块真的可以吗?我应该使用 Edge 模块还是插件?

4

1 回答 1

1

SetTimer是一个 Windows 函数。

为了让它工作,应用程序必须有一个 Windows 消息循环:

您需要在调用线程中调度消息,即使您使用 TimerProc 而不是处理 WM_TIMER

但是 node.js 在 Windows 上使用 IOCP。它不发送消息。

处理此问题的一种方法是在 C++ 代码中使用uv_timer ,但为此,必须使用node- gyp 将 dll 链接到 node.exe(它像共享库一样导出 libuv 函数)。

请注意,此解决方案是跨平台的。

但是您已经使用的另一种方法setInterval更容易并且是跨平台的。

setInterval在引擎盖下使用 uv_timer。

另一种解决方案是在您的本机库中创建另一个线程并从那里调用回调函数。如果您打算使用 SetTimer,则必须在创建的线程中调用它,并且您将需要一个 Windows 消息循环。

于 2016-08-29T01:01:30.713 回答