В этом наброске хочу углубиться в изъезженную тему про работу с формами и объектами на них.

Чтобы что-то сделать с объектом, нам нужно получить его handle — уникальный идентификатор.
Ты наверняка уже сталкивался с api функциями, предназначенными для этих целей. Перечислим их: FindWindow, FindWindowEx, GetWindow. Это далеко не все, но нам их хватит, оговорюсь, что я с GetWindow полностью обхожусь, его мы рассмотрим чуток позднее.

[FindWindow]
синтаксис:
function FindWindow(lpClassName, lpWindowName: PChar): HWND;
HWND это тот же integer, то есть функция возвращает число, handle объекта. Функция работает только для форм, то есть объектов верхнего уровня.
параметры:
lpClassName — класс объекта;
lpWindowName — заголовок, в данном случае формы.
Хочу обратить внимание, что функция находит объект, только если:
переданные класс и заголовок полностью соответствуют классу и заголовку объекта,
заголовок соответствует, а переданный класс nil,
заголовок передан nil, а класс соответствует,
передано nil и nil.
В последнем случае функция возвращает первое по счету окно. Это я к тому, что если FindWindow(nil, ‘wnd.txt — Блокнот’) нам вернет handle окна блокнота, то FindWindow(nil, ‘Блокнот’) или FindWindow(nil, ‘wnd.txt’) нам вернет 0, мы должны знать точные данные об окне. Реализовывать поиск по части заголовка мы будем позже.

[FindWindowEx]
синтаксис:
function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: PChar): HWND;
Здесь у нас всё аналогично, но появляется пара новых параметров:
Parent — handle родительского объекта;
Child — handle дочернего объекта.
Как parent, так и Child имеют право быть нулями.

[пример]
Долго думал, что привести в качестве примера, рассмотрим изъезженное до дыр получение данных из формы логина qip. Как мы знаем (а если не знаем — используем Spy++), форма логина имеет класс TManForm — достаточно редко найдешь форму с таким классом, заголовок нам уже не интересен. На форме стоит TGroupBox, в одном экземпляре, в котором мы находим TComboBox с «ICQ#/Email/SN». Вычислим handle этого объекта:

function GetQIPLoginHandle:integer;
var
  j:integer;
begin
  Result:=0;
  j:=FindWindow('TManForm', nil);
  if j=0 then Exit;
  j:=FindWindowEx(j, 0, 'TGroupBox', nil);
  if j=0 then Exit;
  j:=FindWindowEx(j, 0, 'TComboBox', nil);
  Result:=j;
end;

Если наша функция чего-то не находит, возвращается 0.

[GetWindow]
Эта вещь будет помощней FindWindow и FindWindowEx, синтаксис:
function GetWindow(hWnd: HWND; uCmd: UINT): HWND;
Не похоже на FindWindow, не так ли? Рассмотрим что есть что:
hWnd — handle некоего объекта;
uCmd — команда, действие, указывает как получить новый handle.
Константы для uCmd начинаются с префикса GW_ (от GetWindow), рассмотрим ближе:
GW_CHILD — дочерний объект, первый по счету (их может быть много);
GW_OWNER — по идее должно возвращать handle окна-владельца. Учитываем, что окно-родитель и окно-владелец могут быть разными, это тема для отдельного разговора, оговорюсь лишь, что для определения родителя можно использовать GetParent;
GW_HWNDFIRST, GW_HWNDLAST, GW_HWNDNEXT, GW_HWNDPREV — константы для получения первого, последнего, следующего или предыдущего объекта на этом уровне, то есть когда одинаковый родитель (или его нет).
GW_MAX — честно говоря, не очень понимаю, будет время — разберусь и напишу об этом)
Тут нужно обратить внимание на то, что ни с заголовком, ни с классом объекта функция не работает, нам надо проверять их вручную.

[узнаём заголовок или класс объекта]
Приведу сразу готовые функции, которые использую сам:

function GetCaption(hWnd:HWND):string;
var
  len:integer;
  text:PChar;
begin
  Result:='';
  if hWnd=0 then Exit;
  len:=SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0);
  if len<>0 then begin
    GetMem(text, len+1);
    SendMessage(hWnd, WM_GETTEXT, len+1, integer(text));
    Result:=text;
    FreeMem(text);
  end;
end;

это для заголовка.
Что касается класса:

function GetClass(hWnd:HWND):string;
var
  arr:array[0..255] of char;
begin
  GetClassName(hWnd, arr, SizeOf(arr));
  Result:=string(arr);
end;

На этом пока остановлюсь, в следующих частях жди примеры работы с GetWindow и функции поиска окон, в том числе рекурсивные, основанные на нём. Также, может быть, рассмотрю работу и с меню.

(c) crystalbit, http://parsers.info

Подпишись на rss и следующие части не пройдут мимо)

А в качестве постового сегодня ссылка на случай, если Вам нужно создать резюме в Ростове-на-Дону.