Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.12.2011, 00:05   #1
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию Перебор окон, поиском нужного по параметрам

Доброго времени суток!

Стоит задача:
Найти на десктопе окно с опр. заголовком, текстом, и найти кнопку.



Все это при помощи таймера и EnumWindows. В EnumWindows я передаю в lParam указатель на обьект, с информацией, которую надо искать.
Если все данные совпадают, то как вернуть из EnumWindows измененный обьект?

Или я опять туплю, ведь я передаю только указтель на обьект, и EnumProc не обязательно перепередать этот указатель т.к. данные будут изменены по ссылке на обьект а обьект будет там же.


В EnumProc я передаю 2-ым параметром, указатель как число, на обьект
как использоать в EnumProc данные из обьекта?

Точнее как передать в EnumProc правильно указатель на обьект.

Далее как правильно перебрать все компоненты внутри окна?

Код:
type
  TWindowInf=class
  WindowHWND:HWND;
  WindowClassFull:string;
  WindowTitleFull:string;
  WindowTextFull:string;
  WindowBtnTextFull:string;
  end;
  PWindowInf=^TWindowInf;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

function EnumProc(aHwnd:HWND; lParam:LPARAM):LongBool;
const
  MAX_BUFF=255;
var
  ClassBuff:array[0..MAX_BUFF] of Char;
  TitleBuff:array[0..MAX_BUFF] of Char;
  p:Pointer;
begin
  P:=PWindowInf(lParam);
  ZeroMemory(@ClassBuff,0);
  ZeroMemory(@TitleBuff,0);
  GetClassName(aHwnd,ClassBuff,MAX_BUFF);
  GetWindowText(aHwnd,TitleBuff,MAX_BUFF);
end;

function FindWindowByThis(aClass,aTitle,aText,aBtnText:string):PWindowInf;
var
 Wnd:TWindowInf;
begin
   Wnd:=TWindowInf.Create;
   Wnd.WindowClassFull:=Aclass;
   wnd.WindowTitleFull:=aTitle;
   wnd.WindowTextFull:=aText;
   wnd.WindowBtnTextFull:=aBtnText;
   if EnumWindows(@EnumProc,LPARAM(@Wnd)) then
   Result:=@Wnd;
end;
Человек_Борща вне форума Ответить с цитированием
Старый 28.12.2011, 00:17   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Код:
type
  TWindowInf=class
  WindowHWND:HWND;
  WindowClassFull:string;
  WindowTitleFull:string;
  WindowTextFull:string;
  WindowBtnTextFull:string;
  end;
  //PWindowInf=^TWindowInf;   объекты храняться по ссылке итак, нет нужды в обьявлении указателя на указатель на объект.

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

function GetClassName(h:THandle):string;//она удобнее:)
begin
 SetLength(Result,512);
 SetLength(REsult,GetClassName(h,@Result[1],512));//тут @ может не нужно, не помню.

function EnumProc(aHwnd:HWND; lParam:LPARAM):LongBool;stdcall;//где stdcall был?
var
  ClassName:string;
  P:TWindowInf;
begin
  P:=TWindowInf(lParam);
  Classname:=GetClassName(aHwnd);
  Result:=false;//предполагаем что нашли, значит(если не else) дальше искать не надо
  if ClassName=P.WindowClassFull 
      then P.WindowHWND:=aHwnd
      else Result:=true;//если не нашли ничего, то продолжаем поиск
end;

function FindWindowByThis(aClass,aTitle,aText,aBtnText:string):TWindowInf;
var
 Wnd:TWindowInf;
begin
   Wnd:=TWindowInf.Create;//лучше напишите конструктор классу
   Wnd.WindowClassFull:=Aclass;
   wnd.WindowTitleFull:=aTitle;
   wnd.WindowTextFull:=aText;
   wnd.WindowBtnTextFull:=aBtnText;
   wnd.WindowHWND:=0;
   if EnumWindows(@EnumProc,LPARAM(Wnd)) then
   Result:=Wnd;
end;
набросок я дал, остальные условия допишите сами.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 28.12.2011, 00:21   #3
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Спасибо, понял как делать.
А как перебрать все копоненты внутри окна? Использовать EnumChildWindows, и передовать ему hwnd от EnumWindows?
Человек_Борща вне форума Ответить с цитированием
Старый 28.12.2011, 00:28   #4
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
А как перебрать все копоненты внутри окна? Использовать EnumChildWindows, и передовать ему hwnd от EnumWindows?
вообще да.
но в вашем случае помоему куда проще FindWindowEx применить.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 28.12.2011, 00:41   #5
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Каким образом?
Человек_Борща вне форума Ответить с цитированием
Старый 28.12.2011, 00:48   #6
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Код:
if FindWindowEx(ahwnd,0,'BUTTON',P.WindowBtnTextFull)<>0 then //тогда есть такое окно(кнопка)  нужного окна.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 28.12.2011, 17:02   #7
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Возникли вопросы:
1. Вы правы, лучше FindWindowEx , он же тоже все компоненты перебирает окна aHwnd, начиная с 0 ?

2. Что лучше использовать, тип Record или TObject как у меня?
И если Record. то как им швыряться из функции в функцию?

Код:
type
  TWindowInf = class
    WindowHWND: HWND;
    WindowClassFull: string;
    WindowTitleFull: string;
    WindowTextFull: string;
    WindowBtnTextFull: string;
  end;


function GetControlClass(h: THandle): string;
var
  Buff: array[0..512] of Char;
begin
  GetClassName(h, @Buff, Length(Buff));
  Result := String(Buff);
end;

function GetControlText(h: Thandle): string;
var
  Buff: array of Char;
  BuffLen: Integer;
begin
  BuffLen := GetWindowTextLength(h);
  SetLength(Buff, BuffLen);
  GetWindowText(h, @Buff, BuffLen);
  Result := String(Buff);
end;

function EnumChildProc(aHwnd: HWND; lParam: LPARAM): LongBool; stdcall;
var
  P: TWindowInf;
begin
  P := TWindowInf(lParam);
  if Pos(LowerCase(Trim(p.WindowTextFull)), Trim(GetControlText(aHwnd))) > 0
    then
  begin
    p.WindowTextFull := GetControlText(aHwnd); //Нашли
    Result := False; //прерываем цикл
  end
  else
  begin
    Result := True; //продолжаем искать
  end;
end;

function EnumProc(aHwnd: HWND; lParam: LPARAM): LongBool; stdcall;
var
  ClassName: string;
  Title: string;
  P: TWindowInf;
begin
  P := TWindowInf(lParam);
  Classname := GetControlClass(aHwnd);
  Title := GetControlText(aHwnd);

  if Length(Trim(p.WindowClassFull)) > 0 then //Ищем Класс
  begin
    if Pos(LowerCase(p.WindowClassFull), LowerCase(ClassName)) > 0 then
    begin
      p.WindowClassFull := ClassName;
    end
    else
    begin
      Result := True;
    end;
  end;

  if Length(Trim(p.WindowTitleFull)) > 0 then //Ищем заголовок
  begin
    if Pos(LowerCase(p.WindowTitleFull), LowerCase(Title)) > 0 then
    begin
      p.WindowTitleFull := Title;
    end
    else
    begin
      Result := True;
    end;
  end;

  if Length(Trim(p.WindowTextFull)) > 0 then //Ищем текст в конпонентах окна
  begin
   { if not EnumChildWindows(aHwnd, @EnumChildProc, Integer(p)) then
    begin
      Result := True;
    end; }
  end;

  p.WindowHWND:=aHwnd;
  Result:=True;
end;

function FindWindowByThis(aClass, aTitle, aText, aBtnText: string): TWindowInf;
var
  Wnd: TWindowInf;
begin
  Result:=nil;
  Wnd := TWindowInf.Create; //Написать конструктор, ну пока это тест. проект.
  Wnd.WindowClassFull := Aclass;
  wnd.WindowTitleFull := aTitle;
  wnd.WindowTextFull := aText;
  wnd.WindowBtnTextFull := aBtnText;
  wnd.WindowHWND := 0;
  if EnumWindows(@EnumProc, LPARAM(Wnd)) then
    Result := Wnd;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  p:TWindowInf;
begin
   p:=FindWindowByThis(Edit1.Text,Edit2.Text,Edit3.Text,Edit4.Text);
   Memo1.lines.Clear;
   Memo1.Lines.Add(IntToStr(p.WindowHWND));
   Memo1.Lines.Add(p.WindowClassFull);
   Memo1.Lines.Add(p.WindowTitleFull);
   Memo1.Lines.Add(p.WindowTextFull);
   Memo1.Lines.Add(p.WindowBtnTextFull);
   FreeAndNil(p);
end;
У меня N параметров поиска:
1. Поиск: Заголовок окна(часть заголовка)
2. Поиск: Текст в компонентах окна(Часть текста)
3. Поиск: Класс окна(Часть имени класса)
4. Поиск: Окно принадлежит такому-то списку процессов?
5. Действия: Найти в компонентах окна кнопку с текстом X(Частью текста) или/и классом Y(Частью имени класса) и нажать.
6. Действия: Что-то замутить с владельцем окна.

3. Как выйти из Enum'а окон? Определить что все компоненты найдены.
Была идея повтыкать BOOL переменных, и если все TRUE, то закончить Enum, но чувствую что есть что-то проще.
Человек_Борща вне форума Ответить с цитированием
Старый 31.12.2011, 12:22   #8
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,434
По умолчанию

Вот поправил:
Код:
type
  TWindowInfo = record //Информация об окне
    wHandle: HWND;
    wClass: string;
    wTitle: string;
    wTextClass: string;
    wText: string;
    wButtonClass: string;
    wButtonText: string;
  end;
  PWindowInfo = ^TWindowInfo;

type
  TWindowSearchInfo = record //Информация для поиска
    swClass: string;
    swTitle: string;
    swText: string;
    swAction: SmallInt;
    swButtonClass: string;
    swButtonText: string;
    WindowInfo: PWindowInfo;
  end;
  PWindowSEarchInfo = ^TWindowSearchInfo;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

function ReturnControlText(aHandle: HWND): string;
var
  Buff: array[0..512] of Char;
begin
  GetWindowText(aHandle, @Buff, Length(Buff));
  Result := StrPas(@Buff);
end;

function ReturnControlClass(aHandle: HWND): string;
var
  Buff: array[0..512] of Char;
begin
  GetClassName(aHandle, @Buff, Length(Buff));
  Result := StrPas(@Buff);
end;

function EnumChildProc(aHWND: HWND; alParam: LPARAM): LongBool; stdcall;
var
  P: PWindowSEarchInfo;
  sText, sTextClass: string;
  hText: HWND;
begin
  P := PWindowSearchInfo(alParam);
  sText := ReturnControlText(aHWND);
  sTextClass := ReturnControlClass(aHWND);
  if Pos(LowerCase(p.swText), LowerCase(sText)) > 0 then
  begin
    p.WindowInfo.wText := sText;
    p.WindowInfo.wTextClass := sTextClass;
  end;
end;

function EnumProc(aHWND: HWND; alParam: LPARAM): LongBool; stdcall;
var
  P: PWindowSEarchInfo;
  sClass, sTitle, sText, sTextClass, sButtonClass, sButtonText: string;
  hText: HWND;
begin
  P := PWindowSearchInfo(alParam);
  if IsWindowVisible(aHWND) then
  begin
    if not (p.swClass = EmptyStr) then
    begin
      sClass := ReturnControlClass(aHWND);
      if Pos(LowerCase(p.swClass), LowerCase(sClass)) > 0 then
      begin
        p.WindowInfo.wClass := sClass;
        p.WindowInfo.wHandle := aHWND;
      end;
    end;

    if not (p.swTitle = EmptyStr) then
    begin
      sTitle := ReturnControlText(aHWND);
      if Pos(LowerCase(p.swTitle), LowerCase(sTitle)) > 0 then
      begin
        p.WindowInfo.wTitle := sTitle;
        p.WindowInfo.wHandle := aHWND;
      end;
    end;

    if not (p.swText = EmptyStr) then
    begin
      //Эта функция должна перебрать все компоненты внутри окна aHWND, но перебирает все окна на экране заного. 
      EnumChildWindows(aHWND,@EnumChildProc,LPARAM(P)); 
    end;

  end;
end;

procedure TMainForm.StartBtnClick(Sender: TObject);
var
  aRec: TWindowSearchInfo;
  afRec: TWindowInfo;
begin
  FillChar(aRec, 0, SizeOf(TwindowSearchInfo));
  FillChar(afRec, 0, SizeOf(TwindowInfo));
  aRec.swClass := WindowClassEdit.Text;
  aRec.swTitle := WindowTitleEdit.Text;
  aRec.swText := WindowTextEdit.Text;
  aRec.swAction := WindowActionCombo.ItemIndex;
  aRec.swButtonClass := ButtonClassEdit.Text;
  aRec.swButtonText := ButtonTextEdit.Text;
  aREc.WindowInfo := @afRec;
  if EnumWindows(@EnumProc, Integer(@aRec)) then
  begin
    Log.Lines.Clear;
    log.Lines.Add('Класс: ' + afRec.wClass);
    log.Lines.Add('Заголовок: ' + afRec.wTitle);
    log.Lines.Add('Класс текста: ' + afRec.wTextClass);
    log.Lines.Add('Текст: ' + afRec.wText);
    log.Lines.Add('Класс кнопки: ' + afRec.wButtonClass);
    log.Lines.Add('Текст кнопки: ' + afRec.wButtonText);
    log.Lines.Add('ID окна: ' + IntToStr(afRec.wHandle));
  end;
end;
Теперь другая проблема:
Нужно в окне, найти нужный мне компонент а в нём текст, поиск не должен быть чувствителен к регистру и чтобы можно было искать по части текста.

Я выбрал EnumChildWindows и в передаю ещё HWND нужного мне окна для опытов. Однако функция начинает перебор всех окон на рабочем столе заного(как EnumWindows), что мне совсем не надо.

Как быть?

И правильно ли я обращаюсь с типом record? Работать-то оно работает...
Человек_Борща вне форума Ответить с цитированием
Старый 04.01.2012, 11:00   #9
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

1. С record'ом вы обращаетесь правильно, но до тех пор, пока не захотите записать в типизированный файл - динамические строки тут дадут о себе знать.
2. Например использовать GetWindowText:
Код:
var
  LpStr:PAnsiChar;
begin
  LpStr:=AnsiStrAlloc(1024);
  GetWindowTextA(Memo1.Handle,LpStr,StrLen(LpStr));
  ShowMessage(LpStr);
  StrDispose(LpStr);
end;
Далее, получив текст окна, вы сможете сравнивать как хотите и с чем хотите
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Перебор компонентов окон и построение дерева как у Spy++ Человек_Борща Win Api 5 26.11.2011 04:00
нет нужного компонента Yungo161 Компоненты Delphi 2 26.06.2011 16:12
Поиск нужного скрипта Rost93 JavaScript, Ajax 3 06.06.2011 19:22
Поиск нужного курсора BarakudaX777 Мультимедиа в Delphi 15 15.06.2010 19:17
Отсечение нужного кода -HunteR- Помощь студентам 6 25.06.2008 16:16