2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Запуск и управление программ.
Сообщение04.09.2009, 18:59 
Заблокирован


05/07/09

265
Рязань
Не подскажете, как в делфи написать программу, которая бы запускала любую (наперёд известную) программу и могла бы ею управлять, т.е. имитировать действия оператора?

 Профиль  
                  
 
 Re: Запуск и управление программ.
Сообщение04.09.2009, 19:20 
Заслуженный участник


27/04/09
28128
Надо довольно хорошо разбираться в Windows API. Чтобы написать такую прграмму на любом языке, не только Object Pascal. Функция ShellExecute запускает программу или другой файл, который "умеет" открывать ОС, можно передавать параметры (см. файлы справки Windows SDK, которые распространяются вместе с Delphi). Чтобы управлять программой, надо посылать ей или её окнам и их элементам сообщения ф-ей SendMessage. Можно даже перемещать мышь (SetCursorPos). Но лучше курсором не пользоваться, а напрямую обращаться к окнам программы и не трогать курсор. Если наперёд известная программа поддерживает COM, полезней пользоваться им.

 Профиль  
                  
 
 Re: Запуск и управление программ.
Сообщение04.09.2009, 19:34 
Заслуженный участник
Аватара пользователя


01/08/06
3132
Уфа
Delphi (впрочем, как и другие языки программирования общего назначения, AFAIK) не содержит высокоуровневых средств для подобного рода манипуляций.
Т.е. всё делается низкоуровневыми средствами, основные из которых --- функции Windows API keybd_event, mouse_event.

Если нужно записывать действия оператора, а затем воспроизводить их в автоматическом режиме, можно воспользоваться хуками (Hooks) WH_JOURNALRECORD, WH_JOURNALPLAYBACK --- информация также имеется в документации по API Windows.

А вообще (если отвлечься от Delphi) для подобных вещей есть специальные программы, из которых я знаю только DemoShield.

 Профиль  
                  
 
 Re: Запуск и управление программ.
Сообщение09.09.2009, 13:55 
Заблокирован


05/07/09

265
Рязань
А можно небольшую програмку, как пример, использования подобных функций?

 Профиль  
                  
 
 Re: Запуск и управление программ.
Сообщение09.09.2009, 15:04 
Заслуженный участник
Аватара пользователя


01/08/06
3132
Уфа
У меня есть только опыт управлением "изнутри программы".
Для этого пишется специальная библиотека:

код: [ скачать ] [ спрятать ]
Используется синтаксис Delphi
{$H+,V-,P-}
library RecordEventHooks;

uses
  ShareMem,
  SysUtils,
  Classes,
  Dialogs,
  Windows,
  Messages;

var
  LastEventTime  : Integer = 0;
  FirstTime: Boolean = True;
  DefaultSpeed : Integer = 1;
  CanRecord: Boolean = True;
  CanPlay: Boolean = True;
  MacroFileOpened: Boolean = False;
  Recording: Boolean = False;
  Playing: Boolean = False;
  HookHandle: HHook = 0;
  MacroFileName: string = '';

  MacroFile: file of TEventMsg;
  CurEvent, LastEvent: TEventMsg;


function PlaybackSpeed: Integer; stdcall; export;
begin
  Result := DefaultSpeed;
end;

procedure SetPlaybackSpeed(NewSpeed: Integer); stdcall; export;
begin
  if (NewSpeed >= 0) and (NewSpeed <= 1000) then DefaultSpeed := NewSpeed;
end;

procedure CloseMacroFile;
begin
  if MacroFileOpened then Close(MacroFile);
  MacroFileOpened := False;
end;

procedure ResetHooks; stdcall; export;
begin
  if HookHandle <> 0 then UnhookWindowsHookEx(HookHandle);
  HookHandle := 0;
  CloseMacroFile;
  Playing := False;
  Recording := False;
end;

function RecordMacro(HookCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; export;
{ JournalRecordProc hook procedure }
var Event: TEventMsg;
begin
  Result := CallNextHookEx(HookHandle, HookCode, wParam, lParam);
  case HookCode of
    HC_ACTION: begin
      if not CanRecord then Exit;
      try
        Event := PEventMsg(lParam)^;
        if (Event.message = WM_KEYUP) and ((Event.paramL and $FF)= VK_CANCEL) then
        begin
          ResetHooks;
          ShowMessage('Запись макро прервана пользователем');
        end else Write(MacroFile, Event);
      except
        ResetHooks;
        ShowMessage('Ошибка при записи в файл'  + MacroFileName +
          '. Запись макро прекращена');
        raise;
      end;
    end;
    HC_SYSMODALON: CanRecord := False;
    HC_SYSMODALOFF: CanRecord := True;
  end; {case...}
end;

procedure PlayPause; stdcall; export;
begin
  if Playing then
  begin
    if HookHandle <> 0 then UnhookWindowsHookEx(HookHandle);
    HookHandle := 0;
    Playing := False;
    FirstTime := True;
  end;
end;

function PlayMacro(HookCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; export;
begin
  Result := CallNextHookEx(HookHandle, HookCode, wParam, lParam);
  case HookCode of
    HC_GETNEXT:
    begin
      if not CanPlay then Exit;
      PEventMsg(lParam)^ := CurEvent;
      if FirstTime
      then Result := 0
      else begin
        Result := Integer(CurEvent.Time) - LastEventTime;
        if Result > 0 then
        begin
          if  (CurEvent.Message = WM_MOUSEMOVE)
           or (CurEvent.Message = WM_NCMOUSEMOVE)
           or (CurEvent.Message = WM_NCHITTEST)
           or (CurEvent.Message = WM_MOUSEACTIVATE)
           or (CurEvent.Message = WM_CAPTURECHANGED)
           or (LastEvent.Message = WM_MOUSEMOVE)
           or (LastEvent.Message = WM_NCMOUSEMOVE)
           or (LastEvent.Message = WM_NCHITTEST)
           or (LastEvent.Message = WM_MOUSEACTIVATE)
           or (LastEvent.Message = WM_CAPTURECHANGED)
          then Result := DefaultSpeed;
          if   (CurEvent.Message >= WM_KEYFIRST)
           and (CurEvent.Message <= WM_KEYLAST)
          then begin
            if DefaultSpeed < 100
            then Result := DefaultSpeed
            else if Result < DefaultSpeed
                 then Result := DefaultSpeed;
          end;
        end;
      end;
      LastEventTime := CurEvent.Time;
      FirstTime := False;
    end;
    HC_SKIP:
    begin
      if not CanPlay then Exit;
      if EOF(MacroFile) then
      begin
        ResetHooks;
        ShowMessage('Выполнение макро прекращено');
      end else
        try
          LastEvent := CurEvent;
          Read(MacroFile, CurEvent);
        except
          ResetHooks;
          ShowMessage('Ошибка при чтении из файла'  + MacroFileName +
            '. Выполнение макро прекращено');
          raise;
        end;
    end;
    HC_SYSMODALON: CanPlay := False;
    HC_SYSMODALOFF: CanPlay := True;
  end; {case}
end;

procedure PlayResume; stdcall; export;
begin
  if not Playing and not Recording then
  begin
    if HookHandle = 0
    then HookHandle := SetWindowsHookEx(WH_JOURNALPLAYBACK, PlayMacro, HInstance, 0);
    Assert(HookHandle <> 0,'Не удалось установить Hook!');
    Playing := True;
  end;
end;

procedure SetRecord(const MacroFName: string); stdcall; export;
begin
  MacroFileName := MacroFName;
  Assign(MacroFile, MacroFileName);
  try
    Rewrite(MacroFile);
    MacroFileOpened := True;
    HookHandle := SetWindowsHookEx(WH_JOURNALRECORD, RecordMacro, HInstance, 0);
    Assert(HookHandle <> 0,'Не удалось установить Hook!');
    Recording := True;
  except
    if MacroFileOpened
    then begin
      CloseMacroFile;
      raise;
    end
    else ShowMessage('Ошибка при открытии файла ' + MacroFileName +
           '. Запись макро прекращена');
  end;
end;

procedure PlayRecord(const MacroFName: string); stdcall; export;
begin
  MacroFileName := MacroFName;
  Assign(MacroFile, MacroFileName);
  try
    FirstTime := True;
    Reset(MacroFile);
    MacroFileOpened := True;
    HookHandle := SetWindowsHookEx(WH_JOURNALPLAYBACK, PlayMacro, HInstance, 0);
    Assert(HookHandle <> 0,'Не удалось установить Hook!');
    Playing := True;
  except
    if MacroFileOpened
    then begin
      CloseMacroFile;
      raise;
    end
    else ShowMessage('Ошибка при открытии файла ' + MacroFileName +
           '. Выполнение макро прекращено');
  end;
end;

exports
  SetRecord,
  PlayRecord,
  RecordMacro,
  PlayMacro,
  PlayPause,
  PlayResume,
  ResetHooks,
  PlaybackSpeed,
  SetPlaybackSpeed;

end.


Использование:
Код:
const HookDLL = 'RecordEventHooks.DLL';

procedure SetRecord(const MacroFName: string); stdcall; external HookDLL;
procedure PlayRecord(const MacroFName: string); stdcall; external HookDLL;
procedure PlayPause; stdcall; external HookDLL;
procedure PlayResume; stdcall; external HookDLL;
procedure ResetHooks; stdcall; external HookDLL;
function PlaybackSpeed: Integer; stdcall; external HookDLL;
procedure SetPlaybackSpeed(NewSpeed: Integer); stdcall; external HookDLL;

// Войти в режим записи действий пользователя (выйти из него он может, нажав Ctrl+Break)
// Все действия записываются в файл FileName
SetRecord(FileName);
...
// Установить скорость воспроизведения (в мс между отдельными событиями)
SetPlaybackSpeed(5);
// Войти в режим воспроизведения записанных (в файле FileName) действий пользователя
// Выйти из него пользователь также может, нажав Ctrl+Break
PlayRecord(FileName);


-- Ср сен 09, 2009 19:15:14 --

Правда, говорят, под Вистой может глючить :

http://groups.google.com/group/microsoft.public.win32.programmer.ui/browse_thread/thread/7175392a7dbb2215/234c168f378b2d80?lnk=st&q=wh_journalplayback+vista&rnum=1#234c168f378b2d80

(там есть и рецепт, как это лечится).

 Профиль  
                  
 
 Re: Запуск и управление программ.
Сообщение10.09.2009, 17:27 


10/09/09
13
И кстати, оконные сообщения, посланные (SendMessage) других процессом, с кодом, меньшим, чем WM_USER, будут подавляться системой безопасности Win. Поэтому, arseniiv, это не вариант.

Нужно использовать то, что подсказал всем нам worm2: keybd_event, mouse_event.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 6 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group