11

在 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不能保证每次调用它时都会调用回调,我需要确保每次收到窗口消息时都会调用我的 JS 回调。

4

3 回答 3

11

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

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

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

于 2013-07-19T23:28:34.330 回答
1

我需要为佳能的 EDSDK 执行此操作,这需要消息泵

libuvuv_idle_t是一个很好的候选者:

尽管有这个名字,空闲句柄会在每次循环迭代时调用它们的回调,而不是当循环实际上是“空闲”时</p>

例子:

#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);
    }
}
于 2019-09-12T07:40:29.870 回答
0

我找到了真正的原因。

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

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

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

于 2018-07-27T08:19:31.507 回答