Как использовать другой цикл обработки событий в приложении Win32 GUI - PullRequest
1 голос
/ 01 июня 2019

Я новичок в программировании Win32 API, и я пытаюсь написать клиент xmpp для платформы Windows, используя Win32 API и библиотеки Gloox xmpp. У gloox есть собственный цикл обработки событий, в то время как в Windows GUI также есть цикл обработки сообщений. Мне не очень понятно, как использовать эти две петли вместе.

Из глокс-документа:

Блокирующие и неблокирующие соединения Для каких-то ботов идеально подходит блокирующее соединение (поведение по умолчанию). Все, что делает бот - это реагирует на события, поступающие с сервера. Однако для клиентов конечного пользователя или чего-либо еще с графическим интерфейсом это далеко не идеально.

В этих случаях могут использоваться неблокирующие соединения. Если вызывается ClientBase :: connect (false), функция возвращается сразу после установления соединения. В этом случае программист обязан инициировать получение данных из сокета.

Самый простой способ - периодически вызывать ClientBase :: recv () с требуемым временем ожидания (в микросекундах) в качестве параметра. Значение по умолчанию -1 означает блокировку вызовов до тех пор, пока не будут получены какие-либо данные, которые затем автоматически анализируются.

Цикл сообщений в окне:

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

Окно proc:

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

глокс неблокирующее соединение

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 Ответ

0 голосов
/ 01 июня 2019

Лучшая стратегия IO для этого - это IO с перекрытием.К сожалению, этот метод предназначен только для Windows и не поддерживается выбранной кросс-платформенной библиотекой.

Вы можете использовать API SetTimer () и периодически вызывать метод recv () библиотеки с нулевым тайм-аутом, вОбработчик WM_TIMER.Это создаст дополнительную задержку (ваш компьютер получит сообщение, но ему придется ждать следующего события таймера, чтобы обработать его), или, если вы будете использовать небольшие интервалы, например 20 мс, заряд батареи на ноутбуках или планшетах.

Вы можете использовать блокирующий API с отдельным потоком.Более эффективный с точки зрения производительности, но сложнее в реализации, вам придется перенаправлять сообщения и другие события в поток GUI.Кстати, WM_USER + n пользовательских оконных сообщений - лучший способ сделать это.

...