Форум программистов, компьютерный форум, киберфорум
Nexi99
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Как найти окно в с++/Как найти окно в Windows

Запись от Nexi99 размещена 04.06.2021 в 04:50
Обновил(-а) Nexi99 10.06.2021 в 22:10

Ребята некоторые инклуды не нужны, уберёте их сами или компилятор выкинет их автоматически при сборке. Если написано примечание, значит внизу есть сноски читайте там. Функции и библиотека находятся здесь: Maks_Znah + массивы и вспомогательные функции там по ссылке посмотрите не буду громодить здесь лишний текст.
https://www.cyberforum.ru/blog... g7146.html,
PoiskSimv, strok1, strok11
https://www.cyberforum.ru/blog... g7147.html
Чтобы всё заработало вам понадобятся функции по ссылкам а также массивы которые функции просят объявить.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include "windows.h"
#include "Modul.h"
#include <cstdlib>
#include <tlhelp32.h>
 
using std::cout;
using std::endl;
using std::cin;
 
using namespace std;
HWND g_HWND=0;//Примечание 9.
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam){
    DWORD lpdwProcessId=0;if(g_HWND==hWnd){g_HWND++;}
    GetWindowThreadProcessId(hWnd,&lpdwProcessId);
    if(lpdwProcessId==lParam){g_HWND=hWnd;ret 0;}ret 1;}
 
char*KILL[3]={"TASKKILL /IM ",0," /F /T"};//13/6
char ShetSimvol(char*str,char sm=0){char kol=0;if(str[sm]=='\0')ret 0;for(;str[++kol+sm]!='\0';);ret kol;}
 
char cmd_(char*str,char**comand=KILL,char kol=3){char q=-1;//считает символы вставляемой строки
for(char w=-1;++w<kol;){for(char e=-1;(str[++q]=comand[w][++e])!='\0';);--q;}ret++q;}
 
int _tmain(int argc, _TCHAR* argv[]){setlocale(0,"");Maks_Znah();
char*put="C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe";
char*NameWind="Chrome_WidgetWin_1";//класс окна Хром/Браве/char*NameWind="MozillaWindowClass";//класс окна Мозилы
 
char*er,*ed;
char kol[3]={ShetSimvol(put),0,ShetSimvol(NameWind)};
er=&put[kol[0]-(PoiskSimv(put,kol[0],kol[0])-1)];//устанавливаем указатель на то место где название процесса
kol[1]=ShetSimvol(er);
ed=KILL[1]=new char[++kol[1]];//не забываем добавить единицу под нулл терминатор иначе не удалится память
for(char q=-1;++q<kol[1];)ed[q]=er[q];//переписываем имя процесса/используем одномерный указатель для облегчения 
//нагрузки
char*et=new char[13+6+kol[1]];
cmd_(et);//составляем строку для удаления если придётся использовать system
wchar_t rrrr[30]={};//LPSTR
char tttt[50]={};
cout<<"et "<<et<<" "<<(Sh)kol[2]<<en;//можете вывести строку
 
long stil;
bool ravenstvo=0;
HANDLE Process_[4]={CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)};
PROCESSENTRY32 pe32pr={sizeof(pe32pr)};
 
if(Process32FirstW(Process_[0],&pe32pr)){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););//Примечание 1
for(;!ravenstvo&&Process32NextW(Process_[0],&pe32pr);){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););//Примечание 2
if(ravenstvo&&pe32pr.cntThreads==1){system(et);ravenstvo=0;}}}//если 1ин поток то закрытие некорректно и программа не 
//работает закрываем и далее запускаем иначе перехват и запуск не нужен
STARTUPINFOA start_info={sizeof(start_info)};
PROCESS_INFORMATION proc_info={};
 
for(char w=-1;++w<3&&!ravenstvo;){//3 попытки на запуск программы Примечание 3
CreateProcessA(put,0,0,0,0,0,0,0,&start_info,&proc_info);Sleep(10000);
if(Process32FirstW(Process_[0]=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0),&pe32pr)){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););
for(;!ravenstvo&&Process32NextW(Process_[0],&pe32pr);){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););}}}//
 
if(!ravenstvo)ret 0; kol[1]--;//если программа не запустилась выхожу иначе ищу номер потока
THREADENTRY32 pe32pt={sizeof(pe32pt)};
if(Thread32First(Process_[1]=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,pe32pr.th32ProcessID),&pe32pt)){
for(;pe32pt.th32OwnerProcessID!=pe32pr.th32ProcessID&&Thread32Next(Process_[1],&pe32pt););}//
g_HWND=GetForegroundWindow();// если компьютер не виснет по умолчанию окно на переднем плане
tttt[GetClassNameA(g_HWND,tttt,++kol[2])]='\0';//находим имя класса и копируем его в массив Примечание 4 идентефикация окна по классу
if(strok1(kol[2],1,tttt,NameWind)&&((stil=GetWindowLongPtrA(g_HWND,GWL_STYLE))==919535616||stil==399441920||stil==382664704)){//и стилям
//если нужное окно на переднем плане Примечание 8.
SetWindowLongA(g_HWND,GWL_STYLE,382664704);//Примечание 5
SetWindowPos(g_HWND,HWND_TOPMOST,400,400,400,400,SWP_SHOWWINDOW);}else{//если класс совпадает управляем окном
EnumWindows(EnumWindowsProc,pe32pr.th32ProcessID);//берём предлагаемый дескриптор
tttt[GetClassNameA(g_HWND,tttt,kol[2])]='\0';//GetClassNameA  нулл терминатор не записывает поэтому записываем вручную
if(strok11()&&((stil=GetWindowLongPtrA(g_HWND,GWL_STYLE))==919535616||stil==399441920||stil==382664704)){
SetWindowLongA(g_HWND,GWL_STYLE,382664704);
SetWindowPos(g_HWND,HWND_TOPMOST,400,400,400,400,SWP_SHOWWINDOW);}else{
DWORD rrr[3]={(DWORD)g_HWND};HWND qee;//если не совпадает то ищем дискриптор вручную пока не найдём нужный
for(;--rrr[0];){rrr[1]=pe32pr.th32ProcessID;//поиск в сторону 0/дескриптор чаще ниже g_HWND
if(GetWindowThreadProcessId(qee=(HWND)rrr[0],&rrr[1])==pe32pt.th32ThreadID){//Примечание 6
tttt[GetClassNameA(qee,tttt,kol[2])]='\0';
if(strok11()&&((stil=GetWindowLongPtrA(g_HWND=qee,GWL_STYLE))==919535616||stil==399441920||stil==382664704)){
SetWindowLongA(g_HWND,GWL_STYLE,382664704);
SetWindowPos(g_HWND,HWND_TOPMOST,400,400,400,400,SWP_SHOWWINDOW);break;}}}
if(!rrr[0]){rrr[0]=(DWORD)g_HWND;for(;;){rrr[1]=pe32pr.th32ProcessID;//поиск в положительную сторону
if(GetWindowThreadProcessId(qee=(HWND)++rrr[0],&rrr[1])==pe32pt.th32ThreadID){
tttt[GetClassNameA(qee,tttt,kol[2])]='\0';
if(strok11()&&((stil=GetWindowLongPtrA(g_HWND=qee,GWL_STYLE))==919535616||stil==399441920||stil==382664704)){
SetWindowLongA(g_HWND,GWL_STYLE,382664704);
SetWindowPos(g_HWND,HWND_TOPMOST,400,400,400,400,SWP_SHOWWINDOW);break;}}}}}}
DWORD exit_=0;
if(pe32pr.th32ProcessID==proc_info.dwProcessId){//сравниваем 2 процесса 1ин от CreateProcessA второй от CreateToolhelp32Snapshot
GetExitCodeProcess(proc_info.hProcess,&exit_);//если равны то процесс можно закрыть без ущерба не прибегая к лишней 
//нагрузке
TerminateProcess(proc_info.hProcess,exit_);CloseHandle(proc_info.hProcess);
}else{//в противном случае system
cmd_(et);system(et);}//Примечание 7.
delete et;delete KILL[1];_getch();return 0;}

Я открыл много тем чтобы узнать как найти окно любой запущенной программы
Объясните принцип вывода окна на передний план
Как переключить фокус программы на нужное окно?
Где почитать инструкции о том как выдвинуть окно запущенного процесса на передний план
ну и конечно с ним что-то сделать. Например выдвинуть его на переднйи план.
Было прочитано много инструкций форумов и блогов.
Как оказалось задача очень затруднительная: мне пришлось решить 3 вопроса.
1. Один из пользователей написал что умирает PID запущенного процесса, поэтому приходиться возиться с процессами(за советы спасибо).
2. Далее выяснил сам что умирает не только PID процесса но и окна. Отсюда возникает 3яя проблема.
3. Функция EnumWindows не находит окно пришлось искать вручную.
4. Возникли проблемы с идентефикацией окна.

Примечание 1. Я тестировал этот код на браузерах Mozilla Firefox, Google Chrome и Brave. Последние 2 отрабатываются при закрыти нормально.
Mozilla при закрытии закрывается не полностью, я забивал tasklist и видел что после ручного закрытия окна висит 1ин из процессов. Почему не знаю, поэтому я прописал этот блок для поиска нужного процесса чтобы его полностью завершить, чтобы не перехватить крывой процесс.
В качестве критерия я взял 1ин поток т.к. у меня был глюк такой. Если вы руками запустите процесс и ваша программа его перехватит то он может быть закрыт, далее по коду он будет открыт опять.
Возможно такие глюки не всегда будут вычисляться по одному потоку и вам понадобятся другие критерии чтобы обнаружить такой глюк.
Примечание 2. Можно заметить что я помещаю 2ух байтовое значение в 1ый массив. Я использую латинские символы, если посмотреть на код, а они как раз помещаются в мой массив, функции которые должны преобразовывать их непонятные типы и кодировки либо работают крыво, либо сложные и у меня отпала охота с ними возиться. Также как показала практика я не копирую не нужные названия в массив а сразу сравниваю что уменьшает нагрузку на программу, по этим причинам я не стал использовать функции разработчиков для копирования и преобразования данных.
Примечание 3. Несмотря на 3 попытки которые я дал на запуск программы/процесса бывают случаи когда процесс запускается и сразу же завершается аварийно. Почему это происходит я не знаю. С этим вопросом обращайтесь к тем кто это ПО делал. Если у вас такое происходит то нужно вычислить моменты на основании которых можно запустить программу заново. Тут уже подумаете сами. Я такое видел редко и проблему не решал т.к. эти окна угробили мне 2 месяца чистой выработки по 12 часов в день, может немного меньше но не суть.
Примечание 4. Я ранее упоминал что возникли проблемы с идентификацией окна. Её я проводил по:"Имени класса окна" и "Стилям окна".
Пример. Вы должны чётко знать имя класса окна: у Chrome и Brave это Chrome_WidgetWin_1 у Mozilla- MozillaWindowClass. Как оказалось даже этого
не достаточно т.к. окно имеет много вспомогательных и не нужных окон, в том числе которые функции WinApi могут найти и обработать и вы получите не то что хотели и пришлось ещё возиться со стилями. Окна которые я находил имеют комбинацию стилей:
(WS_CAPTION|WS_MAXIMIZE|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCH ILDREN| WS_SYSMENU|WS_THICKFRAME|WS_OVERLAPPED|WS_MINIMIZEBOX|WS_MAX IMIZEBOX);
17CF0000-399441920/36CF0000-919535616/без WS_MINIMIZE и WS_MAXIMIZE 16CF0000-382664704 этот стиль преобладает если окно не развёрнуто на весь экран.
Если присутствует
WS_MINIMIZEто окно свёрнуто, WS_MAXIMIZE развёрнуто на весь экран, если этот стиль отсутствует то получаем значение 382664704, смотрите выше. Не все окна могут иметь такие настройки.
Примечание 5. Ниже по коду видно что я вызываю функцию SetWindowPos чтобы изменить размер окна. Тут есть нюанс у некоторых окон закрыт доступ к этой возможности, руками окно меняется а программно нет. За это отвечают стили
https://docs.microsoft.com/en-... ass-styles
,должны присутствовать CS_HREDRAW и CS_VREDRAW, если их нет доступ к окну заблокирован, будет меняться только мышкой вручную, но если окно не развёрнуто на весь экран то его размер можно изменить программно, я устанавливаю стиль 382664704 далее флаги взаимосвязаны и окно поддаётся изменению. Для изменения стилей фрейма нужен флаг SWP_FRAMECHANGED. Не совсем понятно, я меняю простые стили и с КЭШем не работаю и установил флаг SWP_SHOWWINDOW ниже.
Примечание 6. Поиск окна. У меня реализована 2ух уровневая модель поиска окна. Вначале вызывается EnumWindows. Если нужное окно не найдено. То начинается поиск через цикл, я меняю дескриптор на единицу и двигаю номер байта вперёд или назад.
Стартовая точка g_HWND, конечная точка нужный дескриптор. Я подозреваю что у функции EnumWindows есть доступ к массиву с этими дескрипторами. Но разработчики забили болт мол зачем вам туда доступ. Повторный вызов EnumWindows не приводит к поиску нужного окна. А если вдруг и находит то знайте что это временно в 100ый раз или более не найдёт у меня тоже так было. Поэтому ручонками приходится работать.
Сначала я иду к 0-ю, после в положительную сторону я запускал этот код раз 100 и у меня отрабатывались все варианты. Если поиск в положительную сторону то ваш дескриптор должен существовать, если его нет цикл станет бесконечным, в этом случае его нужно ограничить либо всё же он должен существовать. Бывали случаи ранее когда окно было слабо идентифицировано, программа в этом случае просто останавливалась. В принципе этот механизм может работать очень быстро, если дескриптора находится не далеко от найденного EnumWindows. Но бывали случаи когда g_HWND был найден на милионных позициях и приходилось вручную отматывать 19.5 млн. чтобы найти нужное окно. Я клоню к тому что изначально я и осуществлял поиск руками без EnumWindows, иногда так дешевле но чаще всего дескриптор не далеко от g_HWND. Поэтому я не могу вам посоветовать как крутить цикл возможно EnumWindows стоит вообще выбросить и начать крутить с 0, идея состоит в том что EnumWindows получает доступ к массиву где есть эти дескрипторы, поэтому я всё же оставил эту функцию хотя возможно и не стоит. В принципе при работе с окнами речь о скорости не идёт вообще, главное выполнить задумку так что смотрите сами.
Примечание 7. Реализовано 2 механизма закрытия процесса. Как уже понятно при запуске мы теряем доступ к PID, а значит теряем и его дескриптор. Чтобы получить этот дескриптор нужно раскапывать привилегии процесса, который мы же и запустили. Уже ребята не обижайтесь тут уже конечно можно и коньки откинуть. Как эти привилегии собственных процессов раскапывать я не разобрался ещё, видимо пока всё разработчики не заблокируют
не успокоятся. Чтобы не грузить программу и голову я решил закрывать процессы функцией system. Кому не сложно напишите
подробный код и инструкцию как это делать, я физически не успеваю всё это делать, я разобрался с окнами а вы можете подсказать как разобраться с процессами. Доступ к дескриптору нужен для модификации, я то её здесь не произвожу поэтому с привилегиями примеров не выставляю.
Примечание 8. Если вы запустите этот код как написано, то будет произведён запуск процесса, будет найдено окно и проделано то что нужно и программа быстро завершится. Вы не заметите как код манипулирует окном, поэтому перед вызовом SetWindowPos необходимо вызвать задержку Sleep(10000). Я собирал это дело в режиме отладки и постоянно проверял переменные и дебажил код поэтому этот вызов не делал.
Примечание 9. Замечал случаи когда g_HWND был верный, сравнивал в проге Spy++ а окно всё равно не было выдвинуто на передний план. Т.к. я тестировал на браузерах то там было окошко о восстановлении вкладок, видимо оно имеет высокий приоритет и не даёт управлять окном, так что наблюдайте за окнами может быть и такое и такие окна стоит закрывать. Или можно отодвинуть другие окна на задний план. Можно также потестировать эту функцию GetLastActivePopup .

Доработанный вариант
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
int _tmain(int argc, _TCHAR* argv[]){setlocale(0,"");Maks_Znah();
 
char*put="C:\\Program Files\\Mozilla Firefox\\firefox.exe";//char*put="C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe";
char*NameWind="MozillaWindowClass";//класс окна Мозилы//char*NameWind="Chrome_WidgetWin_1";//класс окна Хром/Браве
 
char*er,*ed;
char kol[3]={ShetSimvol(put),0,ShetSimvol(NameWind)};
er=&put[kol[0]-(PoiskSimv(put,kol[0],kol[0])-1)];
kol[1]=ShetSimvol(er);
ed=KILL[1]=new char[++kol[1]];
for(char q=-1;++q<kol[1];)ed[q]=er[q];
 
char*et=new char[13+6+kol[1]];
cmd_(et);
cout<<"et "<<et<<en;
 
bool ravenstvo=0;
HANDLE Process_[4]={CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)};
PROCESSENTRY32 pe32pr={sizeof(pe32pr)};
 
if(Process32FirstW(Process_[0],&pe32pr)){//
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););
for(;!ravenstvo&&Process32NextW(Process_[0],&pe32pr);){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););
if(ravenstvo&&pe32pr.cntThreads==1){system(et);ravenstvo=0;}}}
 
STARTUPINFOA start_info={sizeof(start_info)};
PROCESS_INFORMATION proc_info={};
 
for(char w=-1;++w<3&&!ravenstvo;){
CreateProcessA(put,0,0,0,0,0,0,0,&start_info,&proc_info);Sleep(10000);//proc_info.dwProcessId/
if(Process32FirstW(Process_[0]=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0),&pe32pr)){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););
for(;!ravenstvo&&Process32NextW(Process_[0],&pe32pr);){
for(char q=-1;++q<kol[1]&&(ravenstvo=pe32pr.szExeFile[q]==er[q]););}}}//
 
if(!ravenstvo)ret 0;
THREADENTRY32 pe32pt={sizeof(pe32pt)};
if(Thread32First(Process_[1]=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,pe32pr.th32ProcessID),&pe32pt)){
for(;pe32pt.th32OwnerProcessID!=pe32pr.th32ProcessID&&Thread32Next(Process_[1],&pe32pt););}//
WINDOWPLACEMENT plac={sizeof(WINDOWPLACEMENT),0,1};//устанавливаем окно в состояние не свёрнутое и не развёрнутое plac.showCmd=1;
RECT PositonWind={};HWND g_HWND[2]={GetDesktopWindow()};
g_HWND[1]=GetForegroundWindow();char*NameCl=new char[++kol[2]];
NameCl[GetClassNameA(g_HWND[1],NameCl,kol[2])]='\0';
auto okno=[&g_HWND,&plac](){SetWindowPlacement(g_HWND[1],&plac);//Примечание 5в2.
if(GetWindowLongPtrA(g_HWND[1],GWL_STYLE)==382664704){
SetWindowPos(g_HWND[1],HWND_TOPMOST,400,400,400,400,SWP_SHOWWINDOW);ret(bool)1;}ret(bool)0;};//ShowOwnedPopups(g_HWND[1],0);//если нужно и если есть скрываем все всплывающие и диалоговые окна poisk
 
if(strok1(kol[2],1,NameCl,NameWind))okno();
else{DWORD rrr[3]={(DWORD)(g_HWND[1]=g_HWND[0])};
for(;;){rrr[1]=pe32pr.th32ProcessID;//Примечание 6в2.
if(GetWindowThreadProcessId(g_HWND[1]=(HWND)++rrr[0],&rrr[1])==pe32pt.th32ThreadID){
GetWindowRect(g_HWND[1],&PositonWind);//снимаем размеры
if(!PositonWind.bottom)continue;
NameCl[GetClassNameA(g_HWND[1],NameCl,kol[2])]='\0';
if(strok11()&&okno())break;}}}delete NameCl;
 
DWORD exit_=0;
if(pe32pr.th32ProcessID==proc_info.dwProcessId){
GetExitCodeProcess(proc_info.hProcess,&exit_);
TerminateProcess(proc_info.hProcess,exit_);CloseHandle(proc_info.hProcess);}else{
cmd_(et);system(et);}delete et;delete KILL[1];_getch();return 0;}
Примечание 6в2. Функция EnumWindows оказалась полностью бесполезной. Я решил установить стартовую точку на дескриптор рабочего стола, что в конечном итоге позволило выбросить несколько сотен тысяч итераций, а также производить поиск в одном направлении ну и конечно объём проверок удалось уменьшить.
Также я заметил что все мёртвые окна имеют нулевой размер, и решил использовать функции для снятия размера, если окно не имеет размеров что в принципе не нормально то идём в следующую итерацию.
Примечание 5в2. Вызываю функцию SetWindowPlacement чтобы установить состояние окно в положение не свёрнутое и не развёрнутое и получить 1ин стиль для проверки 382664704. Про все положения окон можно почитать здесь https://docs.microsoft.com/en-... showwindow
Размещено в Окна
Показов 902 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.