В этом наброске хочу углубиться в изъезженную тему про работу с формами и объектами на них.
Чтобы что-то сделать с объектом, нам нужно получить его 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 и следующие части не пройдут мимо)
А в качестве постового сегодня ссылка на случай, если Вам нужно создать резюме в Ростове-на-Дону.
Большое спасибо за изъезженную тему :)
Изучать Delphi начал совсем не давно, пишу на С/С++(сказал бы ,что в нем тоже далеко не профи :), понадобился визуальный интерфейс , на С/С++ свой разрабатывать оказалось утомительным делом, использовать готовый вин айпиай в С/С++ тоже не сахар :), изучать MFC не захотелось(поглядел ,там показалось тоже не удобно), почитал ,прикинул,за пару дней ознакомления с Delphi, удалось сделать программу (интерфейс) ,который благодаря информации размещенной вами тут, уже умеет отправлять нужные сообщения программе написанной в С/С++
Приятно)