Как правильно уничтожить окно, запущенное из другого потока?

Цель, которую я пытаюсь достичь, - прослушивать уведомления сеанса о блокировке, разблокировке и т. д. Я должен сделать это в другом потоке из-за архитектуры и избежать блокировки основного потока. Вот что я делаю:


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_WTSSESSION_CHANGE:
        switch (wParam) {
        case WTS_CONSOLE_CONNECT:
        case WTS_SESSION_LOGON:
        case WTS_REMOTE_CONNECT:
        case WTS_SESSION_UNLOCK:
        case WTS_CONSOLE_DISCONNECT:
        case WTS_REMOTE_DISCONNECT:
        case WTS_SESSION_LOGOFF:
        case WTS_SESSION_LOCK:
        case WTS_SESSION_REMOTE_CONTROL:
        case WTS_SESSION_CREATE:
        case WTS_SESSION_TERMINATE:

            break;
        default:
            break;
        }
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    return 0;
}

void startListeningNotifications()
{
    const wchar_t g_szClassName[] = L"myWindowClass";

    WNDCLASSEX wc = {};
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = g_szClassName;
    wc.cbSize = sizeof(WNDCLASSEX);

    if (!RegisterClassEx(&wc))
    {
        return;
    }

    HWND hwnd = CreateWindowEx(NULL, g_szClassName, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
    if (hwnd == NULL)
    {
        return;
    }

    if (!WTSRegisterSessionNotification(hwnd, NOTIFY_FOR_ALL_SESSIONS))
    {
        return;
    }

    ShowWindow(hwnd, SW_HIDE);

    MSG Msg = {};
    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

int main()
{
    std::thread listener(startListeningNotifications);
    listener.join();

    return 0;
}

Проблема, с которой я сейчас сталкиваюсь, заключается в том, что я не знаю, как правильно написать метод stopListeningNotifications(). Я должен каким-то образом уничтожить свое окно и выйти из цикла сообщений. Посоветуйте, как это сделать безопасно. Заранее спасибо.

Вы должны знать, что каждый цикл обработки сообщений выполняется в своем собственном потоке. Так что просто отправить сообщение в это окно не будет хорошей идеей. Я бы попробовал использовать std::condition_variable, чтобы сигнализировать окну, которое должно быть закрыто. Окно приема может просто вызвать свою функцию Close(), если уведомление получено.

πάντα ῥεῖ 26.12.2020 16:27
PostMessageW(hwnd, WM_CLOSE, 0, 0)
RbMm 26.12.2020 16:56

Но безопасен ли этот поток?

Oleg 26.12.2020 17:05

конечно потокобезопасный. что здесь может быть не безопасно?

RbMm 26.12.2020 17:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
622
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предоставлены дескрипторы функций WndProcWM_CLOSE и WM_DESTROY.

case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
case WM_DESTROY:
        PostQuitMessage(0);
        break;

Таким образом, вы можете отправить WM_CLOSE сообщение с hwnd окна, созданного в треде:

PostMessage(hwnd, WM_CLOSE, 0, 0)

Могу ли я отправить это сообщение в любую тему? В моем случае это будет основной поток.

Oleg 26.12.2020 17:07

Вы можете отправлять сообщения в любой поток, даже в тот, который не создавал окно (PostThreadMessage), но в целевом потоке должен быть цикл сообщений.

alex_noname 26.12.2020 17:14

Я уже пробовал это, но это не работает для меня. Но когда я попробовал этот PostMessage() из основного потока (без PostThreadMessage), он работает.

Oleg 26.12.2020 17:15

Публикация WM_CLOSE решила вашу проблему?

alex_noname 26.12.2020 17:24

Да, но я отправляю это из другой темы, я не думаю, что это потокобезопасно.

Oleg 26.12.2020 17:26

Использование PostMessage с дескриптором окна является потокобезопасным.

alex_noname 26.12.2020 17:30

Другие вопросы по теме