如何在nodejs插件中抽取窗口消息?

时间:2013-07-19 02:04:19

标签: c++ node.js winapi v8 libuv

在Windows nodejs插件中,我创建了一个窗口,用于接收消息。

Handle<Value> MakeMessageWindow(const Arguments &args) { // exposed to JS
    ...
    CreateWindow(L"ClassName", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0);
    ...
}

我有一个wndproc功能。

Local<Function> wndProc;
LRESULT APIENTRY WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    // pack up the arguments into Local<Value> argv
    wndProc->Call(Context::GetCurrent()->Global(), 3, argv);
}

现在我需要提取消息。通常,你会做类似

的事情
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) 
{
     TranslateMessage(&msg);
     DispatchMessage(&msg);
}

...但这不起作用,因为它只会阻止v8事件循环。

如何以不会阻止v8的方式提取Windows消息,并允许我在窗口收到消息时调用JS函数?

我认为libuv会扮演一个角色,但我不确定如何从一个单独的线程上运行的C安全地调用JS函数,特别是从uv_async_send is not guaranteed to invoke a callback every time you call it开始,我需要确保我的JS回调是每次收到窗口消息时都会调用。

3 个答案:

答案 0 :(得分:11)

我的错误是试图在V8线程上创建窗口。相反,uv_thread_create应该用于调用在新线程上创建窗口的函数,然后继续执行自己的消息泵循环。

然后,wndproc函数需要以线程安全的方式将收到的消息保存到队列中,然后使用uv_async_send通知V8线程消息已到达。

然后在消息入队后调用V8线程上的函数(传递给uv_async_init)。该函数(线程安全地)将每个待处理消息从队列中弹出并调用JS回调。

答案 1 :(得分:1)

我需要对requires a message pump的佳能EDSDK进行此操作。

libuv的uv_idle_t是一个很好的选择:

  

尽管名称如此,但空闲句柄将在每次循环迭代时调用其回调,而不是在循环实际上是“空闲”时

示例:

#include <uv.h>

uv_idle_t* idle = new uv_idle_t();
uv_idle_init(uv_default_loop(), idle);
uv_idle_start(idle, idle_winmsg);

void idle_winmsg (uv_idle_t* idle) {
    MSG msg;
    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

答案 2 :(得分:0)

我找到了这个的真正原因。

Node.js事件循环将陷入对I / O的轮询,并且鉴于没有待处理的未完成I / O操作,事件循环将进入睡眠状态。

idleprepare在Node.js事件循环执行的I / O轮询之前运行,但是没有安排任何工作,您最多只能看到1或2个回调。

没有解决方案,因为没有Win32消息API可用于向I / O完成端口发出信号。您必须在单独的线程中运行Win32消息循环。