【问题标题】:How do I pump window messages in a nodejs addon?如何在 nodejs 插件中泵送窗口消息?
【发布时间】:2013-07-18 04:53:20
【问题描述】:

在 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 并允许我在窗口接收到消息时调用 JS 函数的方式发送 Windows 消息?

我认为 libuv 会发挥作用,但我不确定如何安全地从运行在单独线程上的 C 调用 JS 函数,尤其是在 uv_async_send is not guaranteed to invoke a callback every time you call it 之后,我需要确保每次调用我的 JS 回调收到窗口消息的时间。

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 很棒的信息。您是否偶然有一个 repo 或 node 模块来完成此操作?我也想做同样的事情。
    • 你的方法奏效了吗?我在将回调函数传递给 uv_async_send 时遇到问题,一旦调用了函数 uv_thread_create,我就无法获取回调函数。即使是持久句柄也无法解决 - 我也在 SO 中发布了这个问题。stackoverflow.com/questions/31159029/…
    • 您是否拥有或知道使用此技术的代码仓库?这正是我正在采取的方法。
    【解决方案2】:

    我需要为佳能的 EDSDK 执行此操作,requires a message pump

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

    【讨论】:

      【解决方案3】:

      我找到了真正的原因。

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

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

      没有解决此问题的方法,因为没有可用于指示 I/O 完成端口的 Win32 消息 API。您必须在单独的线程中运行 Win32 消息循环。

      【讨论】:

        猜你喜欢
        • 2018-03-29
        • 2016-03-29
        • 2018-02-02
        • 1970-01-01
        • 1970-01-01
        • 2011-01-30
        • 1970-01-01
        • 2010-12-07
        • 1970-01-01
        相关资源
        最近更新 更多