Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Перехват нажатия кнопки и подмена значения


Автор: Twiddle 13.7.2009, 02:03
Приветствую уважаемые! Помогите самоучке решить сложную задачу. Заранее спасибо!
Есть программа с постоянным именем процесса. Заголовок окна всегда постоянный. На нем есть:
ComboBox, много Static, 2х Edit и 2 кнопки с постоянным заголовком. Задача:
Наша программа  висит просто в памяти возможно свернутая (не активно окно). Когда в чужой программе нажимается кнопка с текстом "Продолжить" то значение в первом эдите меняется на нужное нам; программно мышка кликает на одно из Static и после этого уже эти данные передаются дальше. Основная сложность в том что хендлы в чужой программе каждого элемента меняются. Возможно поможет то что статик по которому нужно кликнуть всегда начинается с "Привет:" а в эдите всегда присутствует первым символ либо "х", либо "у", либо "0" и следующий набор символов постоянный вернее не постоянный а постоянно их кол-во. Находить кнопки и нажимать их, ставить галочки итп я смог, а вот тут проблема. Если без использования DLL будет вообще супер. Один раз отлавливал нажатия клавиш не хуком а таймером - и код меньше и понравилось больше ;). Возможно ещё поможет то что нам известны размеры элементов и они все разные. Очень прошу не помидоров а помощи. 

Автор: niteo 13.7.2009, 09:20
Пробуй Субклассинг использовать.

Автор: Twiddle 13.7.2009, 16:18
 smile или ссылку где про это почитать. 
Спасибо.
Так, прозрение: а что если при появлении родительского окна (ловим по заголовку), отслеживаем нажатие на кнопку (постоянный заголовок у неё), как кнопка нажата успеваем в темп или буффер как правильно называется не знаю уж простите,загружаем все заголовки всех дочерних окон, ищем в этом по маскам нужное нам ("Привет:*" и "Х????????????") у найденого узнаем хендл, меняем в этих эдитах содержимое на то что нужно нам и собственно все готово. Только два вопроса: как реализовать и желательно без DLL и будет ли успевать все подменяться. 

Автор: niteo 13.7.2009, 18:42
Это про Субклассинг для своего окна
    http://forum.vingrad.ru/forum/topic-69246.html
Гдето в этой же ветке было и про инжект в чужой процесс. Без использования DLL

Добавлено через 3 минуты и 37 секунд
Почему хук не юзаешь? Удобная весчь, проще субклассинка с инжектом. Вообще субклассинг нужно юзать для более "глобальных" вещей. Для всего остального сойдут и хуки.

Автор: Twiddle 13.7.2009, 18:49
Хук боюсь использовать потому что многие антивирусы будут ругаться, не хочется каждый раз выключать АнтиВирус. 

Автор: niteo 13.7.2009, 19:01
У меня ни НОД ни Каспер не ругаются. Они не могут на сам ХУК ругаться. Они ругаются только на КОД. ХУК это стандартнай виндовый инструмент.

Автор: Twiddle 13.7.2009, 19:21
Ну допустим будет хук. Это только пол беды. Основная беда в том что нам надо при нажатии кнопки заменть значения эдитов а определить хендл этих эдитов что бы это сделать у меня не получается т.к. там не постоянный заголовок, вернее постояннен только первый символ и общее кол-во. , а по классу не получается т.к. на форме чужой программы много объектов одного класса. =( Второй день уже одержим идеей, читаю вес мануалы, сейчас штрудирую форум, нашел много интерсеного но нужного пока пшик.. =( 

Автор: niteo 13.7.2009, 19:22
Цитата

  при появлении родительского окна (ловим по заголовку), 

  FindWindow

Цитата

  отслеживаем нажатие на кнопку (постоянный заголовок у неё), 


  SetWindowsHookEx

Цитата

  загружаем все заголовки всех дочерних окон, ищем в этом по маскам нужное нам ("Привет:*" и "Х????????????") у найденого узнаем хендл, меняем в этих эдитах содержимое на то что нужно  нам и собственно все готово


  EnumChildWindows

Этого будет достаточно ;)
 В EnumChildWindows заодно и значения будешь в Edit-ах менять

Автор: Twiddle 13.7.2009, 19:43
Нашел вот такой вот код может кому то же полезно будет. 
Код

function EnumChildProc(Wnd: hWnd; lParam: LongInt): Boolean; stdcall;
var
  Buff: array[0..MAXCHAR - 1] of Char;
begin
  Result := True;
  GetClassName(Wnd, Buff, MAXCHAR);
  if String(Buff) = PChar(lParam) then
    Result := Succeeded(SendMessage(Wnd, WM_SETTEXT, 0, Integer(PChar('1111'))));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
begin
  S := 'TEdit';
  EnumChildWindows(FindWindow(nil, 'Form1'), @EnumChildProc, Integer(@S[1]));
end; 


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

Автор: Twiddle 15.7.2009, 01:49
Вот один человек за что ему спасибо подсказал как сделать, но мой мозг не может это превратить в код. Помогите пожалуйста, с меня пиво.
Цитата

Получаешь первое дочернее окно с помощью FindWindowEx или GetWindow с определенным параметром. Теперь repeat, получаешь заголовок, с помощью pos проверяешь наличие подстроки в заголовке, если есть то break. Теперь с помощью GetWindow получаешь следующее, потом until эта переменная равна нулю. В итоге получишь или хэндл в твоей переменной, или 0 если нет такого

и про хук нужной нам кнопки в нужном окне, хендл кнопки и окна находиться без проблем. Заранее спасибо. 

Автор: niteo 15.7.2009, 12:48
Блин, посмотри в DRKB. Там примеров по такой же теме полно. есть на 90% такие как тебе надо.
Все просто. Берешь ЧУЖОЕ окно. Ставишь на контрол ХУК. На каждое отрабатываение события, пробегаешься в цикле по УЖЕ ОТОБРАННЫМ контролам (Отобрать можешь их в EnumChildWindows, там в рекурсии отберешь какие надо контролы) smile

Автор: Twiddle 15.7.2009, 21:42
Ладно с хуком потом, не могу понять в чем тут косяк?
Код

var
z1,z2,:pansichar;
zz:hwnd;
begin
z2:='Kitty';
z1:='Hello'+z2+'!'; // Error =(  wtf? 
zz:=findwindow(nil,z1);

Автор: Romikgy 15.7.2009, 21:55
Код

var
z1,z2,:ansistring;
zz:hwnd;
begin
z2:='Kitty';
z1:='Hello'+z2+'!'; // Error =(  wtf? 
zz:=findwindow(nil,pansichar(z1));

Автор: Twiddle 15.7.2009, 22:46
Спасибо, осталось тока с хуком помучиться... =( 

Автор: Twiddle 22.7.2009, 23:18
Кто нить может конкретно помочь за хорошее пиво? Кто не пьет пиво можем  договориться yf аналогичное вознаграждение... =\ Тупо надо перехватить нажатие кнопки. При нажатии выполняется мой код который я уже написал с горем-пополам. Пасибо заранее... Писать можно в пм.
PS: не ругайтесь на меня  smile 

Автор: Keeper89 23.7.2009, 01:11
Конкретно помочь - это весь код написать? 
niteo, в принципе расписал последовательность действий, осталось только поискать примеры.
З.Ы. Кстати с каким приложением идет работа если не секрет?

Автор: niteo 23.7.2009, 07:36
Чуть грубовато, но.. это глобальный хук на мышку и клаву.
По событию, делаешь WindowFromPoint и юзаешь..

Код

function HookProc(Code: integer; WParam: word; LParam: Longint): Longint; stdcall;
var
  msg: PEVENTMSG;
begin
  if Code >= 0 then begin
     result := 0;
     msg := Pointer(LParam);
     with Form1 do
       case msg.message of
         WM_MOUSEMOVE: ;// Двигаем мышой msg.ParamL - это Х msg.ParamH - Это У
         WM_LBUTTONDOWN: ;// Нажали ЛКМ
         WM_LBUTTONUP:   ; // Отпустили ЛКМ
         WM_RBUTTONDOWN: ; // Нажали ПКМ
         WM_RBUTTONUP:   ; // Отпустили ПКМ
         WM_KEYUP:       ;// Отпустили кнопочку
         WM_KEYDOWN:   ;// Нажали кнопочку
       end;
  end else
     result := CallNextHookEx(HookHandle, code, WParam, LParam);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  HookHandle := SetWindowsHookEx(WH_JOURNALRECORD, @HookProc, HInstance, 0);
  if HookHandle = 0 then
    MessageDlg(IntToStr(GetLastError), mtInformation, [mbOK], 0);
end;



С локальным хуком, чтобы его привязать на какое то не свое приложение, тебе прийдется делать DLL. Весь вышеперечисленный код переносишь в DLL и все...

Код

library MegaHook;
uses
  Windows, Messages;
var
  SysHook: HHook = 0;

function SysMsgProc(Code: Integer; WParam: LongInt; LParam: LongInt): LongInt; stdcall;
begin
  if Code > 0 then
  begin
    ...
  end
  else
    Result := CallNextHookEx(SysHook, Code, WParam, LParam);
end;

procedure Hook(Flag: Boolean); export; stdcall;
begin
  if Flag then
    SysHook := SetWindowsHookEx(WH_GETMESSAGE, @SysMsgProc, HInstance, 0)
  else
    begin
      UnhookWindowsHookEx(SysHook);
      SysHook:=0;
    end;
end;

exports Hook;

begin
end.



И программа которая юзает dll-ку с хуком
Код


procedure TForm1.Button1Click(Sender: TObject);
var
  Hook: MyProcType;
begin
  HDLL := LoadLibrary(PChar('MegaHook.dll'));
  if HDLL > HINSTANCE_ERROR then
  begin
    @Hook := GetProcAddress(HDLL, 'Hook');
    Hook(True);
  end
  else
    MessageDlg('плохо с DLL.', mtError, [mbIgnore], 0);
end;

procedure TForm1.Button2Click(Sender: TObject);

var
  Hook: MyProcType;
begin
  if HDLL > HINSTANCE_ERROR then
  begin
    @Hook := GetProcAddress(HDLL, 'Hook');
    Hook(False);
  end;
End;


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