如何在 win32 gui 应用程序中使用另一个事件循环

Posted

技术标签:

【中文标题】如何在 win32 gui 应用程序中使用另一个事件循环【英文标题】:How to use another event loop in win32 gui application 【发布时间】:2019-06-01 09:53:13 【问题描述】:

我是 win32 api 编程新手,我正在尝试使用 win32 api 和 gloox xmpp 库为 windows 平台编写 xmpp 客户端。 gloox 有自己的事件循环,而 windows GUI 也有消息循环。我不是很清楚如何一起使用这两个循环。

来自 gloox 文档:

阻塞与非阻塞连接 对于某些类型的机器人,阻塞连接(默认行为)是理想的。机器人所做的只是对来自服务器的事件做出反应。然而,对于最终用户客户端或任何带有 GUI 的东西来说,这远非完美。

在这些情况下,可以使用非阻塞连接。如果调用 ClientBase::connect( false ),则函数在连接建立后立即返回。然后由程序员负责从套接字开始接收数据。

最简单的方法是定期调用 ClientBase::recv() 并使用所需的超时时间(以微秒为单位)作为参数。默认值 -1 表示调用阻塞,直到收到任何数据,然后自动解析。

窗口消息循环:

   while (GetMessage(&msg, NULL, 0, 0))
    
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    
    return msg.wParam;

窗口进程:

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

    TCHAR str[100];
    StringCbPrintf(str, _countof(str), TEXT("Message ID:%-6x:%s"), msg, GetStringMessage(msg));
    OutputDebugString(str);
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    switch (msg)
    
    case  WM_CREATE:
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &rect);
        DrawText(hdc, TEXT("DRAW TEXT ON CLIENT AREA"), -1, &rect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        break;
    
    return DefWindowProc(hWnd, msg, wParam, lParam);

gloox 阻塞连接

  JID jid( "jid@server/resource" );
  Client* client = new Client( jid, "password" );
  client->registerConnectionListener( this );
  client->registerPresenceHandler( this );
  client->connect();// here will enter event loop

gloox 非阻塞连接

Client* client = new Client( ... );
ConnectionTCPClient* conn = new ConnectionTCPClient( client, client->logInstance(), server, port );
client->setConnectionImpl( conn );
client->connect( false );
int sock = conn->socket();
[...]

我不是很清楚我该怎么做

定期调用 ClientBase::recv() 并使用所需的超时时间(以微秒为单位)作为参数

有计时器吗?还是多线程编程?还是有更好的解决方案?

任何建议表示赞赏

谢谢

【问题讨论】:

【参考方案1】:

最好的 IO 策略是重叠 IO。不幸的是,该方法仅适用于 windows,您选择的跨平台库不支持。

您可以使用 SetTimer() API,并在 WM_TIMER 处理程序中定期调用库的 recv() 方法,超时为零。这将引入额外的延迟(您的 PC 会收到一条消息,但它必须等待下一个计时器事件来处理它),或者如果您使用 20 毫秒等小间隔,则会消耗笔记本电脑或平板电脑的电池。

您可以将阻塞 API 与单独的线程一起使用。在性能方面更高效,但更难实现,您必须将消息和其他事件编组到 GUI 线程。 WM_USER+n 自定义窗口消息通常是最好的方法,顺便说一句。

【讨论】:

以上是关于如何在 win32 gui 应用程序中使用另一个事件循环的主要内容,如果未能解决你的问题,请参考以下文章

如何使用“pip”安装“win32gui”?

使用 win32gui 使窗口居中

win32gui:如何获取窗口的状态栏文本?

win32gui 选择两个同名窗口

即使使用 Win32GUI,cx_Freeze 也会闪烁 cmd 窗口

如何从 Perl 完全改变 Win32 标题栏的外观?