Все окна приложений управляются различными функциями winapi через свои дескрипторы.
Поэтому неплохо бы знать как их получать.
Рассмотрим функцию findwindow.
findwindow(cn,wn:pchar): hwnd;
cn - имя класса.
wn - имя окна(caption), если = nil, то ищется любое окно этого класса.
Функция возвращает дескриптор окна или 'nil' при неудачном поиске.
- (с.8) Для определения имени класса чужого приложения воспользуйтесь,
поставляемой с delphi, программой winsight 32 через spyfind
window. Лучше иметь только нужное окно в этот момент.
Для, всем известного калькулятора, получение дескриптора его окна
будет выглядеть так :
var h : hwnd;
begin
h:=findwindow('scicalc','Калькулятор');
end;
Есть еще одна функция позволяющая определять дескриптор окна.
getnextwindow(h:hwnd,c:word):hwnd;
h - окно от которого вести отсчет.
с = gw_hwndnext - искать следующее окно.
c = gw_hwndprev - искать предыдущее окно.
Если окна не находится, то возвращается 0.
А еще можно считать заголовок окна (и потом по нему искать хендл).
getwindowtext(h:hwnd,str:pchar,kol:word):integer;
str - строка куда считывать.
kol - количество символов.
Получение списка окон
var
wnd : hwnd;
buff: array [0..127] of char;
begin
listbox1.clear;
wnd := getwindow(handle, gw_hwndfirst);
while wnd <> 0 do begin {Не показываем:}
if (wnd <> application.handle) and {-Собственное окно}
iswindowvisible(wnd) and {-Невидимые окна}
(getwindow(wnd, gw_owner) = 0) and {-Дочернии окна}
(getwindowtext(wnd, buff, sizeof(buff)) <> 0)
then begin
getwindowtext(wnd, buff, sizeof(buff));
listbox1.items.add(strpas(buff));
end;
wnd := getwindow(wnd, gw_hwndnext);
end;
listbox1.itemindex := 0;
end;
Получение списка процессов
var
hsnap:thandle;
pe:tprocessentry32;
begin
listbox1.clear;
pe.dwsize:=sizeof(pe);
hsnap:=createtoolhelp32snapshot(th32cs_snapprocess,0);
if process32first(hsnap,pe) then begin
listbox1.items.add(pe.szexefile);
while process32next(hsnap,pe) do listbox1.items.add(pe.szexefile);
end;
end;
Как получить дескриптор окна другого приложения и сделать его активным?
Использование функции windows api findwindow() - простейший способ нахождение окна,
при условии, что известен его заголовок или имя оконного класса.
Если Вам известна только часть заголовка окна
(например 'netscape - ' + 'какой-то неизвестный url'),
Вам нужно использовать функцию enumwindows() для получения всех окон,
затем вызывать функцию getwindowstext()
и getclassname для поиска нужного окна.
Следующий пример находит первое окно, содержащее совпадающую часть заголовка окна
и полностью совпадающее название оконного класса (если он задан)
и делает это окно активным.
type
pfindwindowstruct = ^tfindwindowstruct;
tfindwindowstruct = record
caption : string;
classname : string;
windowhandle : thandle;
end;
function enumwindowsproc(hwindow : hwnd;lparam : longint) : bool
{$ifdef win32}
stdcall;
{$else} ;
export;
{$endif}
var lpbuffer : pchar;
windowcaptionfound : bool;
classnamefound : bool;
begin
getmem(lpbuffer, 255);
result := true;
windowcaptionfound := false;
classnamefound := false;
try
if getwindowtext(hwindow, lpbuffer, 255) > 0 then
if pos(pfindwindowstruct(lparam).caption, strpas(lpbuffer)) > 0
then windowcaptionfound := true;
if pfindwindowstruct(lparam).classname = '' then
classnamefound := true else
if getclassname(hwindow, lpbuffer, 255) > 0 then
if pos(pfindwindowstruct(lparam).classname, strpas(lpbuffer)) > 0 then
classnamefound := true;
if (windowcaptionfound and classnamefound) then
begin
pfindwindowstruct(lparam).windowhandle := hwindow;
result := false;
end;
finally
freemem(lpbuffer, sizeof(lpbuffer^));
end;
end;
function findawindow(caption : string;classname : string) : thandle;
var windowinfo : tfindwindowstruct;
begin
with windowinfo do
begin
caption := caption;
classname := classname;
windowhandle := 0;
enumwindows(@enumwindowsproc, longint(@windowinfo));
findawindow := windowhandle;
end;
end;
procedure tform1.button1click(sender: tobject);
var thewindowhandle : thandle;
begin thewindowhandle := findawindow('netscape - ', '');
if thewindowhandle = 0 then
showmessage('window not found!') else
bringwindowtotop(thewindowhandle);
end;
Ниже приведена процедура, позволяющаю отправлять нажатия в любой элемент управления
(window control), способный принимать ввод с клавиатуры.
Вы можете использовать эту технику чтобы включать клавиши numlock, capslock и scrolllock под windows nt.
Та же техника работает и под windows 95 для capslock и scrolllock, но не работает для клавиши numlock.
Обратите внимание, что приведены четыре поцедуры: simulatekeydown() - эмулировать нажатие клавиши (без отпускания)
simulatekeyup() - эмулировать отпускание клавиши simulatekeystroke() - эмулировать удар по клавише (нажатие и отпускание) и
sendkeys(), позволяющие Вам гибко контролировать посылаемые сообщения клавиатуры.
simulatekeydown(), simulatekeyup() и simulatekeystroke() получают коды виртуальных клавиш (virtural key) (вроде vk_f1). Процедура
simulatekeystroke() получает дополнительный параметр, полезный при эмуляции нажатия printscreen. Когда этот параметр равен нулю
весь экран будет скопирован в буфер обмена (clipboard). Если дополнительный параметр равен 1 будет скопированно только активное
окно.
Четыре метода "button click" демонстрируют использование: buttonclick1 - включает capslock buttonclick2 - перехватывает весь экран в
буфер обмена (clipboard). buttonclick3 - перехватывает активное окно в буфер обмена (clipboard). buttonclick4 - устанавливает фокус в
edit и отправляет в него строку.
Пример:
procedure simulatekeydown(key : byte);
begin
keybd_event(key, 0, 0, 0);
end;
procedure simulatekeyup(key : byte);
begin
keybd_event(key, 0, keyeventf_keyup, 0);
end;
procedure simulatekeystroke(key : byte; extra : dword);
begin
keybd_event(key,extra,0,0);
keybd_event(key,extra,keyeventf_keyup,0);
end;
procedure sendkeys(s : string);
var
i : integer;
flag : bool;
w : word;
begin
{get the state of the caps lock key}
flag := not getkeystate(vk_capital) and 1 = 0;
{if the caps lock key is on then turn it off}
if flag then
simulatekeystroke(vk_capital, 0);
for i := 1 to length(s) do
begin
w := vkkeyscan(s[i]);
{if there is not an error in the key translation}
if ((hibyte(w) <> $ff) and (lobyte(w) <> $ff)) then
begin
{if the key requires the shift key down - hold it down}
if hibyte(w) and 1 = 1 then
simulatekeydown(vk_shift);
{send the vk_key}
simulatekeystroke(lobyte(w), 0);
{if the key required the shift key down - release it}
if hibyte(w) and 1 = 1 then
simulatekeyup(vk_shift);
end;
end;
{if the caps lock key was on at start, turn it back on}
if flag then
simulatekeystroke(vk_capital, 0);
end;
procedure tform1.button1click(sender: tobject);
begin
{toggle the cap lock}
simulatekeystroke(vk_capital, 0);
end;
procedure tform1.button2click(sender: tobject);
begin
{capture the entire screen to the clipboard}
{by simulating pressing the printscreen key}
simulatekeystroke(vk_snapshot, 0);
end;
procedure tform1.button3click(sender: tobject);
begin
{capture the active window to the clipboard}
{by simulating pressing the printscreen key}
simulatekeystroke(vk_snapshot, 1);
end;
procedure tform1.button4click(sender: tobject);
begin
{set the focus to a window (edit control) and send it a string}
application.processmessages;
edit1.setfocus;
sendkeys('delphi is rad!');
end;
wm_copydata для пересылки данных между формами
\ В файле проекта:
var
i: integer;
hmainform:hwnd;
copydatastruct:tcopydatastruct;
paramstring:string;
wparam,lparam:integer;
begin
\ ищем главное окно приложения, вместо caption - nil,
\ поскольку к заголовку главного окна может добавиться заголовок mdichild
\ (нужно позаботиться об уникальности имени класса главной формы)
hmainform:= findwindow('tmainform',nil);
if hmainform = 0 then
begin
application.initialize;
application.createform(tfrmmain,frmmain);
for i:=1 to paramcount do
tmainform(application.mainform).openfile(paramstr(i));
application.run;
end
else
begin
paramstring:='';
for i:=1 to paramcount do
begin
\ запихиваем все параметры в одну строку с разделителями №13
paramstring:=paramstring+paramstr(i)+ #13;
end;
\ создаем запись типа tcopydatastruct
copydatastruct.lpdata:=pchar(paramstring);
copydatastruct.cbdata:=length(paramstring);
copydatastruct.dwdata:=0;
wparam:=application.handle;
lparam:=integer(@copydatastruct);
\ отсылаем сообщение wm_copydata главному окну открытого приложения
sendmessage(hmainform,wm_copydata,wparam,lparam);
application.terminate;
end;
end.
\ Обработчик сообщения wm_copydata
procedure tmainform.copydata(var msg: twmcopydata);
var
paramstr:string;
copydatastructure:tcopydatastruct;
i:integer;
len:integer;
begin
copydatastructure:= msg.copydatastruct^;
paramstr:='';
len:= copydatastructure.cbdata;
for i:=0 to len-1 do
begin
paramstr:=paramstr+(pchar(copydatastructure.lpdata)+i)^;
end;
i:=0;
while not(length(paramstr)=0) do
begin
if isdelimiter(#13,paramstr,i) then
begin
openfile(copy(paramstr,0,i-1));
paramstr:=copy(paramstr,i+1,length(paramstr)-i-1);
end;
inc(i);
end;
inherited;
end;