Работа с окнами Java-приложений из Delphi

Введение

На сегодняшний день существует очень много программистов, которые разрабатывают на Java, и они очень востребованы.

Но не будем забывать, что Delphi в свое время также была очень популярна, в первую очередь тем, что очень быстро можно было реализовать приложение почти любой сложности. Сейчас Delphi также довольно популярная среда разработки, потому что развивается.

Но вот сейчас все больше приложений появляется, написанных на Java. С этими приложениями необходимо работать разработчикам других систем. Когда работаете с окном чужого приложения, обычно заполняются какие-то поля ввода, сворачиваются или разворачиваются окна в операционной системе.

В этой статье мы рассмотрим, как можно заполнить текстовые поля в Java-приложении из Delphi приложения. Скажу сразу, что данная статья подходит только для активных окон, то есть тех, которые имеют фокус. Кроме этого, данная статья подойдет для любых приложений, которые имеют фокус, в независимости от того, на каком языке программирования они написаны.

Смысл заполнения полей (обращение к контролам) любого активного приложения сводится к тому, что мы будем эмулировать нажатие клавиш на клавиатуре. Мы из буфера обмена вставим в Java-приложение текст. Ну а если быть более точным, то наша задача заключается в том, чтобы заполнить форму ввода логина и пароля Java-приложения из нашего приложения Delphi.

Исследование окон приложений при помощи Microsoft Spy++

С обычными Windows-окнами работать из Delphi очень просто. Они имеют контролы, название классов контролов легко посмотреть, а вот что касается Java-приложения, то в нем идет одно главное окно, класс контрола мы не знаем, чтобы обратиться к нему.

Если не верите, давайте же увидим вместе. Для этих целей нам понадобиться приложение Microsoft Spy++. Отличное приложение для работы с окнами в операционной системе. Является одной из частей Visual Studio, но также его можно скачать и отдельным приложением. Достаточно заглянуть на официальный сайт или воспользоваться услугами поисковой системы.

В приложении Microsoft Spy++ мы будем тестировать  приложение Блокнот (Notepad), а также любое приложение, написанное на Java.

Запускаем в системе приложение Блокнот, открываем Microsoft Spy++ и в общем дереве находим нужное нам окно. У меня это выглядит следующим образом:

Анализ приложения Блокнот в Microsoft Spy++
Анализ приложения Блокнот в Microsoft Spy++

Как видите, в блокноте у нас есть как минимум один контрол с классом Edit (поле для ввода текста). К нему мы можем очень просто обращаться из любого приложения, написанного на любом языке программирования. Теперь давайте посмотрим, как у нас обстоят дела с приложением, написанном на Java:

Анализ приложения Java в Microsoft Spy++
Анализ приложения Java в Microsoft Spy++

Microsoft Spy++ показывает только главное окно программы, никаких контролов и классов у приложения на Java не находит, хотя поле для ввода текста и кнопки присутствуют. Это связано с тем, что приложения, написанные на Java не разрабатываются на основе визуальных библиотек, например, VCL/FireMonkey и другие, здесь все контролы вырисовываются.

Работа с окнами Java-приложения из Delphi

Как я сказал ранее, мы будем эмулировать нажатие клавиш на клавиатуре. Поэтому данный метод подойдет для любых активных приложений, которые имеют фокус. Для этих целей мы будем использовать функцию keybd_event, хотя никто не запрещает использовать SendInput.

Для начала давайте вспомним задачу, которая перед нами стоит. Мы должны из буфера обмена заполнить форму ввода логина и пароля, разработанную на Java.

Сама форма ввода логина и пароля выглядит следующим образом:

Форма ввода логина и пароля в приложении Java
Форма ввода логина и пароля в приложении Java

Для начала необходимо в буфер обмена поместить логин и пароль. Чтобы мы знали, что в буфере именно наш логин и пароль, необходимо придумать какой-нибудь префикс, например:

procedure TFormPass.ActionCopyToClipBoardExecute(Sender: TObject);
var
 loginpass:WideString;
begin
   try       
    loginpass:='ваш_логин#ваш_пароль';
    Clipboard.AsText:='Пароли для Java '+loginpass;
   except
    on e:Exception do
   end;
end;

Это делается для того, чтобы наше приложение не срабатывала каждый раз, когда в буфере находятся какие-то данные. Если в буфере есть словосочетание Пароли для Java (Вы можете придумать свое резервное слово, по которому будете отслеживать, что находится в буфере обмена), то будет заполняться форма логина и пароля, а в противном случае будет происходить обычная вставка из буфера обмена.

Смотрите как реализовано в моем примере. Заполнение формы ввода логина и пароля происходит при нажатии сочетания клавиш Ctrl+V, поэтому необходимо зарегистрировать Hotkey на данные горячие клавиши, чтобы потом мы могли его перехватить:

  private
    { Private declarations }
   id1:Integer;
   procedure OnHotKey(var Msg: TWMHotKey); message WM_HOTKEY;

А на событие создание формы напишем следующий код:

procedure TFormPass.FormCreate(Sender: TObject);
begin
   try
    id1:=GlobalAddAtom('Hotkey1');
    RegisterHotKey(Handle, id1, MOD_CONTROL, ord('V'));
   except
    on e:Exception do
   end;
end;

Теперь, когда пользователь нажимаем в системе Ctrl+V, мы можем производить какие-либо действия. Не забывайте только потом убирать регистрацию HotKey:

procedure TFormPass.FormDestroy(Sender: TObject);
begin
   UnregisterHotKey(Handle, id1)
end;

Теперь давайте приступим к реализации непосредственного той части кода, которая отвечает за заполнение формы логина и пароля:

procedure CopyToClipboard(const aText:string);
var
 wText:WideString;
begin
 if Win32Platform=VER_PLATFORM_WIN32_NT then
  begin
   wText:=aText;
   TClipboardAccess(Clipboard).SetBuffer(CF_UNICODETEXT,wText[1],(Length(wText)+1)*2)
  end
 else
  Clipboard.AsText:=aText
end;
 
 
procedure TFormPass.OnHotKey(var Msg: TWMHotKey);
var
 login,pass:string;
 Data:DWORD;
 StrData:PWideChar;
 str1,str2:WideString;
begin
   try
    if Msg.HotKey=id1 then
     begin
      if OpenClipboard(Handle) then
       begin
        Data:=GetClipboardData(CF_UNICODETEXT);
        StrData:=PWideChar(GlobalLock(Data));
        GlobalUnlock(Data);
       end;
      CloseClipboard;
      Str1:='Пароли для Java '+loginpass;
      str2:=StrData;
      if str1 <> str2 then
       begin
        keybd_event(VK_CONTROL,0,KEYEVENTF_KEYUP,0);
        keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_EXTENDEDKEY, 0);
        keybd_event(VK_INSERT,MapVirtualKey(VK_INSERT, 0), KEYEVENTF_EXTENDEDKEY, 0);
        keybd_event(VK_INSERT,MapVirtualKey(VK_INSERT, 0), KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
        keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
        exit;
       end;
      login:=Copy(loginpass,1,pos('#',loginpass)-1);
      pass:=Copy(loginpass,pos('#',loginpass)+1,length(loginpass));
      //вставляем логин
      CopyToClipboard(login);
      keybd_event(VK_CONTROL,0,KEYEVENTF_KEYUP,0);
      keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_EXTENDEDKEY, 0);
      keybd_event(VK_INSERT,MapVirtualKey(VK_INSERT, 0), KEYEVENTF_EXTENDEDKEY, 0);
      keybd_event(VK_INSERT,MapVirtualKey(VK_INSERT, 0), KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
      keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
      keybd_event(VK_TAB,MapVirtualKey(VK_TAB, 0),KEYEVENTF_EXTENDEDKEY,0);
      keybd_event(VK_TAB,MapVirtualKey(VK_TAB, 0),KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0);
      sleep(100);
      //вставляем пароль
      Application.ProcessMessages;
      CopyToClipboard(pass);
      keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_EXTENDEDKEY, 0);
      keybd_event(VK_INSERT,MapVirtualKey(VK_INSERT, 0), KEYEVENTF_EXTENDEDKEY, 0);
      keybd_event(VK_INSERT,MapVirtualKey(VK_INSERT, 0), KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
      keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
     end;
   except
    on e:Exception do
   end;
end;

Процедура CopyToClipboard отвечает за то, чтобы текст ложился в буфер в правильной кодировке, без иероглифов. Далее у нас идет обработка нашего HotKey. Проверяем, какое сочетание клавиш нажал пользователь, если Ctrl+V, то нам нужно проверить, что находится в буфере обмена, если логин и пароль, то разделяем логин и пароль. Сначала помещаем в буфер логин, затем эмулируем нажатие клавиш Shift+Insert (аналог Ctrl+V в Windows) при помощи keybd_event. Самое главное здесь, не забывать эмулировать не только нажатие клавиш, но и также делать так, чтобы клавиш в итоге была отжата.

После того, как логин вставлен в нужное поле, необходимо в буфер поместить пароль. Помещаем пароль и эмулируем нажатие клавиши Tab, чтобы фокус перешел на поле ввода пароля. Затем все просто, опять эмулируем нажатие клавиши Shift+Insert, чтобы из буфера вставить пароль.

Далее можно перейти клавишей Tab на кнопку Ок и эмулировать нажатие клавиши Enter, таким образом пользователю не придется нажимать какие-либо кнопки вообще.

Если же, в буфере обмена находится не логин и пароль, то мы просто эмулируем нажатие Shift+Insert, чтобы наше приложение не блокировало вставку из буфера обмена.  Логин и пароль у нас заполняется теперь автоматически, давайте посмотрим, как это выглядит в Блокноте:

Эмуляция нажатия клавиш из Delphi приложения
Эмуляция нажатия клавиш из Delphi приложения

Как видите, наше приложение извлекло из буфера обмена логин, затем нажала клавишу Tab и затем извлекло из буфера обмена пароль.

Заключение

Если Вы не знаете, как можно чужому окну (в поля ввода и др.) передать какие-либо данные из своего приложения, то самый простой способ – это произвести эмуляцию нажатия клавиш на клавиатуре.

Но не стоит забывать, что данный вариант будет работать только в том случае, если приложение, которому необходимо передать данные, имеет фокус, то есть, оно активно. Если же приложение свернуто, находится в трее или еще что-то, то есть вариант: отправить ему сообщение, обратиться к классу контрола, все это реализовать можно, но конкретно с приложениями Java у вас возникнут проблемы, если не использовать данный метод.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Была ли эта статья полезна?

Статьи по теме

Оставить комментарий

Пожалуйста, авторизуйтесь чтобы добавить комментарий.
  Подписаться  
Уведомление о