Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Эмулирование действия пользователя


Автор: Prospekt 22.12.2012, 09:53
Задача для меня очень необычная, подозреваю, что решения может и не быть.

Есть программа, написаная не мной, скорее всего на Delphi (или CBuilder). Мне требуется сделать надстройку над этой программой, не перекомпилируя её. Что должна делать программа:
1) считывать данный из Label, расположение на экране которых известно и постоянно.
2) отправлять сообщения нажатия кнопок (расположение которых тоже известно).

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

Почему я думаю, что эта задача может иметь решение? Есть такая программа как героекополка (для Heroes 3), которая автоматичеки загружает сейф, покупает в таверне героя, и если новый герой (на месте купленного) не тот, который нужен, происходит опять загрузка сейфа и т.д.

Автор: DarkProg 22.12.2012, 13:08
Для этого вам нужно отправить "другой" програмке соответствующее сообщение используя функцию SendMessage http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms644950(v=vs.85).aspx.

Координаты мыши узнать легко, а вот нажатие левой кнопки мыши выполняется вот так.

Код

    //нажимаем левую кнопку мыши по координатам
    SendMessage(hwnd,WM_LBUTTONDOWN,MK_LBUTTON,MAKELONG(pt.x,pt.y));
    //отпускаем левую кнопку мыши по координатам
    SendMessage(hwnd,WM_LBUTTONDOWN,0,MAKELONG(pt.x,pt.y));


WinAPI одинаково на всех языках, так что примеры можете смотреть на любом языке, суть от этого не меняется.
Главное понимать что искать. Удачи.

Автор: Vas 22.12.2012, 21:27
Цитата(DarkProg @  22.12.2012,  13:08 Найти цитируемый пост)
Координаты мыши узнать легко, а вот нажатие левой кнопки мыши выполняется вот так.

Нафига ему координаты мыши?

Надо искать окно, например, по заголовку, что-то из раздела FindWindow, а потом, перебирая дочерние окна, находить их Handle и слать уже сообщение по SendMessage

Добавлено через 8 минут и 37 секунд
Вот когда-то в молодости писал, запуск приложения в режиме SW_HIDE, поиск окна по заголовку, потом поиск дочерних окон, если их класс (TEdit, запускаемые проги были писаны на дельфях, но не мной) то запоминаем и уже им шлем нужные параметры smile 
P.S. за код не ругать, давно это было  smile 
Код

Var
    hWnd,hList,hPass:THandle;
    Temp:PChar;
    Control:array [0..127] of char;
    counter,count:integer;
    UserName,UserPass:string;
Begin
     OkBtn.Enabled:=False;
     counter:=0; count:=0; hPass:=0;
     ShellExecute(Handle,'open',PChar(FileStr),nil,nil,SW_HIDE);
     repeat
           hWnd:=FindWindow(nil,'Connect');
           Application.ProcessMessages;
     until hWnd<>0;
     SetWindowText(hWnd,PChar('Соединение с базой: '+ListBox1.Items[ListBox1.ItemIndex]));
     ShowWindow(hWnd,SW_RESTORE);
     repeat
           hList:=GetWindow(hWnd, GW_CHILD);
           Application.ProcessMessages;
     until hList<>0;
     While (Counter<>2) AND (Count<>10)  do
           begin
                if hList<>0 then
                   GetClassName(hList, Control, SizeOf(Control))
                else
                    Control:='';
                if (Control='TEdit') OR (Control='Edit') then
                    begin
                         counter:=counter+1;
                         if counter=1 then
                            hPass:=hList;
                    end;
                if Counter<>2 then
                   hList:=GetWindow(hList, GW_HWNDNEXT);
                Count:=Count+1;
           end;
     if Counter=2 then
        begin
             UserName:=GetPassString('******','UserName','');
             Temp:=StrNew(PChar(UserName));
             SendMessage(hList,WM_SETTEXT,0,integer(Temp));
             StrDispose(Temp);
             UserPass:=GetPassString('*******','AutoSave','');
             UserPass:=Coder(UserPass);
             Temp:=StrNew(PChar(UserPass));
             SendMessage(hPass,WM_SETTEXT,0,integer(Temp));
             StrDispose(Temp);
//             ActivateKeyboardLayout(latin,KLF_REORDER);
       end
     else
         ShowMessage('Не могу передать имя пользователя!');
//     StatusBar1.SimpleText:=IntToStr(hWnd)+' '+IntToStr(count)+' '+IntToStr(Counter)+' '+IntToStr(hList)+' '+Control;
     OkBtn.Enabled:=True;

Автор: Prospekt 23.12.2012, 12:59
Спасибо за ответы.

Я сделал так:
1) Сначало вывел список всех окон, и среди них нашел нужное окно типа MainForm.
2) Путем рекурентного поиска выводил все подокна для даного окна. Таким образом вывел дерево графических объектов для начального окна.
Но тут загвоздка, FindWindowEx() принципиально не хочет находить Label, а именно они мне очень нужны.
Почитал немного, оказалось, что Label - это типа как и не окно (вобщем Гейтс и здесь кинул), и таким образом получить handle не получится.
И что делать? Должен же быть какой-то способ добраться до этих Label. Как это сделать своими силами разобраться не могу.

Пардон, это уже другая тема, поэтому создам тему в соотвествующей ветке форума.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)