Загрузка...

C++ WinAPI / How to properly activate a window and switch keyboard focus to it in a foreign thread

Thread in C/C++ created by brediska Dec 17, 2021. (bumped Dec 20, 2021) 433 views

  1. brediska
    brediska Topic starter Dec 17, 2021 Banned 2794 May 30, 2021
    Я почитала инструкции которые здесь описаны https://docs.microsoft.com/en-... g-messages, тема довольно объёмная, сложная, примеров очень мало. Значит я нахожу дескриптор окна по этому алгоритму(в дальнейшем его можно переделать на более простой если система конечно не запрещает отправлять сообщения к не вызывающим потокам) https://www.cyberforum.ru/blog... g7148.html, далее после 64ой строчки дописываю код.
    Code
    tagMSG MSG;
    cout<<"не допустимый идентификатор потока ERROR_INVALID_THREAD_ID "<<ERROR_INVALID_THREAD_ID<<en;//выдаёт 1444
    cout<<"GetLastError "<<GetLastError()<<en;
    tagGUITHREADINFO GUITHREADINFO={sizeof(GUITHREADINFO)};

    cout<<"PeekMessageA "<<PeekMessageA(&MSG,g_HWND[1],WM_KEYFIRST,WM_KEYLAST,PM_QS_SENDMESSAGE)<<en;//PM_NOREMOVE/Примечание 1
    cout<<"GetLastError "<<GetLastError()<<en;//
    cout<<"PostThreadMessageA "<<PostThreadMessageA(pe32pt.th32ThreadID,WA_ACTIVE,WA_ACTIVE,(LPARAM)GetForegroundWindow())<<en;//Примечание 2.
    cout<<"GetLastError "<<GetLastError()<<en;//
    cout<<"GetGUIThreadInfo "<<GetGUIThreadInfo(pe32pt.th32ThreadID,&GUITHREADINFO)<<en;//Примечание 3.
    cout<<"GetLastError "<<GetLastError()<<en;//
    Примечание 1. По идее данная функция должна создавать очередь или давать информацию о ней, в моём случае она пуста. Я пробовала и сразу сообщение посылать.
    cout<<"PeekMessageA "<<PeekMessageA(&MSG,g_HWND[1],WA_ACTIVE,WM_KEYLAST,PM_QS_SENDMESSAGE)<<en;//не знаю или это корректно. Результата нет.
    Примечание 2. По идее эта функция должна посылать сообщение в другой поток, обычно для этого требуются бешеные привилегии и такие функции как правило не работают. Хотя в инструкции сказано что такие привилегии нужны если идёт работа с удалённым рабочим столом.
    Я посылаю команду на активацию и переключения реагирования клавиатуры поэтому 2 раза указываю WA_ACTIVE. Последним параметром я пишу
    о том что нужно снять активацию с текущего окна, т.е. любого окна верхнего уровня, т.к. работаю с дебагом то понятно что на переднем плане
    компилятор а не запускаемая программа. В инструкции сказано что можно 0 писать, может система сама снимает активацию. Это очень странно что её нужно снимать с 1го окна и переводить
    на другое возникает вопрос как работать во многопотоке, там что тоже активация постоянно переключается и создаётся впечатления что активация не снимается.
    Примечание 3. Получаю информацию.
    В конечном итоге получаю ошибку 1159 что говорит о некой синхронизации не совсем понятно почему если я укзала, что нужно снять с верхнего окна активацию и переключиться на
    g_HWND[1]. Проверил дескриптор окна он верный, номер потока тоже да и в принципе здесь записано так if(GetWindowThreadProcessId(g_HWND[1]=(HWND)++rrr[0],&rrr[1])==pe32pt.th32ThreadID)...
    что в принципе проверяет возвращается ли номер потока с участием этого процесса ну и конечно дескриптора окна. Хотя можно и вручную *****
    разницы нет.
    Покажите пример. как эти функции выполнют такую задачу.
     
  2. Replacer
    Replacer Dec 20, 2021 ARTIFICIAL SUICIDE 99 Jul 21, 2021
    PeekMessage не может создавать очередь для сообщений, так как этим занимается сама система и мы не имеем прямого доступа к системным структурам (если говорим о RING 3). Она может только проверять стек потока на нааличие сообщения и если оно существует - обрабатывать. Если стек или сообщения на этот момент пустые (самого сообщения нет в стеке потока), то имеет смысл проверить существование первых двух параметров.

    Рекомендую использовать для этого SetFocus

    Реализуются мьютексы или атомарные классы. Также, как было тобой замечено - каждый поток и процесс имеет свои привилегии исполнения: r, w, x, rwx, rw, rx и прочие комбинации. Если я не ошибаюсь, то вроде PrivilegeCheck показывает права выполнения, опять же, если я не ошибаюсь

    Что говорит FormatMessage?
     
  3. brediska
    brediska Topic starter Dec 21, 2021 Banned 2794 May 30, 2021
    Replacer,
    С какими параметрами посоветуете вызвать эту функцию, и ещё вопрос , можно ли посылать сообщения из консоли, может нужен WinMain? Мне было бы удобнее из консоли, я хочу одну программку сделать. Может это тоже одна из причин почему сообщение не посылается. В инструкции не сказано про это ничего.
    Я вот так записала
    C
    WCHAR rt[1000];  DWORD_PTR pArgs[1000];
    cout<<"GetLastError "<<GetLastError()<<en;
    cout<<"PostThreadMessageA "<<PostThreadMessageA(pe32pt.th32ThreadID,WA_ACTIVE,WA_ACTIVE,0)<<en;
    cout<<"GetLastError "<<GetLastError()<<en;
    cout<<"FormatMessage "<<FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ARGUMENT_ARRAY,0,0,LANG_SYSTEM_DEFAULT,
    rt,1000,(va_list*)pArgs)<<en;
    cout<<"GetLastError "<<GetLastError()<<en;
    wprintf(rt);
    Результат такой
    GetLastError 1400
    PostThreadMessageA 0
    GetLastError 1159
    FormatMessage 29
    GetLastError 1159
    Операция успешно завершена.\r\n
    Я запускала хром. Ошибка 1400 возникает не всегда. Дескриптор прогой Spy++ проверила - соответствует, заголовок окна был от этой темы на форуме. Функция GetWindowRect сворачивает и разворачивает окно. Иногда возникает ошибка 5ть. Я не знаю что означает этот результат и что нужно передавать в функцию на некоторые параметры. Я передавала сообщение WA_ACTIVE по этому его индекс 0 т.к. оно одно.
    \r\n в консоли не отображаются
     
  4. Replacer
    Replacer Dec 22, 2021 ARTIFICIAL SUICIDE 99 Jul 21, 2021
    brediska,
    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER
    . Вообще, надо было сказать раньше, что через нее можно было бы отформатировать вывод ошибки. Тут мой косяк, об этом правда стоило сказать ранее.

    Пробуй связку SendMessage вместе с ReplyMessage, только учти, что SendMessage не вернет значение, пока не обработается сообщение в другом потоке (которое ты отправила). Можно проверить, обрабатывается ли в текущее время отправленное сообщение, вызвав InSendMessage.

    Ну, WinMain используется по стандарту кодинга по винду, вот (хотя ничего не такого не будет, если захочешь использовать кастомные EP с объявляением APIENTRY). Тебе тогда нужно будет вызывать саму консоль в начале функции.

    Поэтому и есть смысл обрабатывать ошибки.

    C
    //Получаем ID ошибки и выводим в MessageBoxW для наглядности
    void GetErrorWin32() {
    DWORD ErrId = GetLastError();
    HLOCAL wStrBuff = NULL; //Буффер для строки

    FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER),
    NULL, ErrId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wStrBuff, 0, NULL);

    //Выводим "сообщение" ошибки (можно воспользоваться wprintf, если нет желания вызывать MessageBoxW)
    MessageBoxW(NULL, wStrBuff, L"Win32 Err", MB_OK);
    }
    GetWindowRect принимает хендл (HWND) окна и указатель на RECT структуру.
     
Top
Loading...