Все окна приложений управляются различными функциями WinApi через свои дескрипторы. Поэтому неплохо бы знать как их получать.
Рассмотрим функцию FindWindow.
FindWindow(CN,WN:PChar): HWnd; CN - имя класса. WN - имя окна(Caption), если = nil, то ищется любое окно этого класса.
Функция возвращает дескриптор окна или 'nil' при неудачном поиске.
- (с.8) Для определения имени класса чужого приложения воспользуйтесь, поставляемой с Delphi, программой WinSight 32 через Spy\Find 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;