Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.03.2025, 12:08   #1
paxan86
Пользователь
 
Регистрация: 18.05.2011
Сообщений: 53
По умолчанию не получается нажать на кнопку да в диалоге

Приветствую всех, пытаюсь нажать на кнопку да, но никак не выходит
Код:
procedure TForm1.Timer2Timer(Sender: TObject);
var
  h1,h2: HWND;
  Rect:TRect;
begin
  h1 := FindWindow(nil, 'CCleaner');
  if  h1 <> 0  then
  Button1.Caption:= 'CCleaner';
    begin
      h2 := FindWindowEx(h1, 0,'Button', '&Да');
      if  h2 <> 0  then
        begin
          Button1.Caption:= 'h2 Найдена';
          GetWindowRect(h2,Rect);
          Form1.Caption:= (IntToStr(Rect.Left)+' '+IntToStr(Rect.Top));
          SetCursorPos(Rect.Left+10,Rect.Top+10);
          Mouse_Event(MOUSEEVENTF_LEFTDOWN, Rect.Left+10, Rect.Top+10, 0, 0);
          Mouse_Event(MOUSEEVENTF_LEFTUP, Rect.Left+10, Rect.Top+10, 0, 0);
         end;
      end;
end;
или так тоже не выходит
Код:
 SendMessage(h2, WM_LBUTTONDOWN, 0, 0);
SendMessage(h2, WM_LBUTTONUP, 0, 0);
Без имени.jpg

так же ещё вопрос, при потере фокуса в моём приложение, не работает SetCursorPos, почему так происходит?

Заранее благодарен за ответы!

Последний раз редактировалось paxan86; 02.03.2025 в 12:16.
paxan86 вне форума Ответить с цитированием
Старый 03.03.2025, 01:12   #2
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,926
По умолчанию

А просто на своем компьютере вы пробовали использовать CCleaner? Он там работает?
А то Вики говорит что
"В начале 2024 года компания Avast, владелец CCleaner, перестала оказывать услуги в России и Беларуси в связи с санкциями Евросоюза. Таким образом, CCleaner не работает на территории России и Беларуси".
northener вне форума Ответить с цитированием
Старый 03.03.2025, 06:15   #3
paxan86
Пользователь
 
Регистрация: 18.05.2011
Сообщений: 53
По умолчанию

CCleaner прекрасно работает, проблема в том что клика просто не происходит, вручную диалог реагирует отлично....
paxan86 вне форума Ответить с цитированием
Старый 03.03.2025, 13:05   #4
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 186
По умолчанию

у меня Lazarus, но думаю в Delphi будет работать.
Я сделал первую программу - одна форма с заголовком окна (caption) 'appForm1'.
На этом окне одна кнопка с надписью 'myButton1'.
Если нажать на эту кнопку, то что-то делается.
Как из другой программы нажать на эту кнопку?

Я сделал вторую программу, вот её текст. На её главном окне одна кнопка, щёлкаем по ней и выполняется код отправки сообщения в первую программу, которая должна в этот момент быть запущена.

Код:
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows, Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);

var
  win1_hdl: hWnd;
  win1_btn_hdl: hWnd;
  btn_text: array [0 .. 2002] of char;
begin
    win1_hdl:=FindWindow( nil, 'appForm1' );
 //   ShowMessage( 'win1='+IntToStr( win1_hdl ) );
    if win1_hdl=0
    then begin
      ShowMessage( 'appForm1 not found' );
      exit;
    end;

    win1_btn_hdl:=FindWindowEx( win1_hdl, 0, nil, 'myButton1' );
//    ShowMessage( 'btn='+IntToStr( win1_btn_hdl ) );

    if win1_btn_hdl=0
    then begin
      ShowMessage( 'myButton1 not found' );
      exit;
    end;

    PostMessage( win1_hdl, WM_COMMAND, BN_CLICKED, win1_btn_hdl );

end;

end.
Сообщение отправляется через PostMessage, но можно и через SendMessage если надо блокироваться.

Последний раз редактировалось DeepFlake; 03.03.2025 в 13:07.
DeepFlake вне форума Ответить с цитированием
Старый 04.03.2025, 09:19   #5
paxan86
Пользователь
 
Регистрация: 18.05.2011
Сообщений: 53
По умолчанию

Спасибо! , попробую , основное различие в строчке postmessage, вечером испытаю
paxan86 вне форума Ответить с цитированием
Старый 05.03.2025, 20:10   #6
paxan86
Пользователь
 
Регистрация: 18.05.2011
Сообщений: 53
По умолчанию

Цитата:
Сообщение от DeepFlake Посмотреть сообщение
у меня Lazarus, но думаю в Delphi будет работать.
Я сделал первую программу - одна форма с заголовком окна (caption) 'appForm1'.
На этом окне одна кнопка с надписью 'myButton1'.
Если нажать на эту кнопку, то что-то делается.
Как из другой программы нажать на эту кнопку?

Я сделал вторую программу, вот её текст. На её главном окне одна кнопка, щёлкаем по ней и выполняется код отправки сообщения в первую программу, которая должна в этот момент быть запущена.

Код:
procedure TForm1.Button1Click(Sender: TObject);

var
  win1_hdl: hWnd;
  win1_btn_hdl: hWnd;
  btn_text: array [0 .. 2002] of char;
begin
    win1_hdl:=FindWindow( nil, 'appForm1' );
 //   ShowMessage( 'win1='+IntToStr( win1_hdl ) );
    if win1_hdl=0
    then begin
      ShowMessage( 'appForm1 not found' );
      exit;
    end;

    win1_btn_hdl:=FindWindowEx( win1_hdl, 0, nil, 'myButton1' );
//    ShowMessage( 'btn='+IntToStr( win1_btn_hdl ) );

    if win1_btn_hdl=0
    then begin
      ShowMessage( 'myButton1 not found' );
      exit;
    end;

    PostMessage( win1_hdl, WM_COMMAND, BN_CLICKED, win1_btn_hdl );

end;

end.
Сообщение отправляется через PostMessage, но можно и через SendMessage если надо блокироваться.
к сожалению так ничего и не получается, видимо где-то у меня ошибка, но где))
Код:
procedure TForm1.Button1Click(Sender: TObject);
begin
  shellexecute(0,nil,'C:\Program Files\CCleaner\CCleaner64.exe',' /delete "%appdata%\Microsoft\Windows\Recent\*" 1',nil,SW_HIDE);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  h1,h2: HWND;
begin
  h1 := 0;
  h2 := 0;
  h1 := FindWindow(nil, 'CCleaner');
  if  h1 <> 0  then
    begin
      h2 := FindWindowEx(h1, 0, nil, '&Да');
      if  h2 <> 0  then
      begin
        PostMessage( h1, WM_COMMAND, BN_CLICKED, h2 );
        SendMessage( h1, WM_COMMAND, BN_CLICKED, h2 );
      end;
    end;
  label1.Caption := cardinal(h1).ToString;
  label2.Caption := cardinal(h2).ToString;
end;


Снимок экрана 2025-03-05 222943.jpg

Последний раз редактировалось paxan86; 05.03.2025 в 20:42.
paxan86 вне форума Ответить с цитированием
Старый 05.03.2025, 21:14   #7
cllc
Пользователь
 
Регистрация: 17.01.2020
Сообщений: 14
По умолчанию

Код:
PostMessage( h1, WM_COMMAND, BN_CLICKED shl 16 or 6 {Control ID}, h2 );
согласно https://learn.microsoft.com/en-us/wi...ols/bn-clicked
Если не сработает, можно попробовать Энтер кнопке послать:
Код:
    Sendmessage(h2, WM_KEYDOWN, VK_RETURN, 1 or MapVirtualKey(VK_RETURN, 0) shl 16);
    Sendmessage(h2, WM_KEYUP, VK_RETURN, 1 or MapVirtualKey(VK_RETURN, 0) shl 16);
cllc вне форума Ответить с цитированием
Старый 07.03.2025, 13:20   #8
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 186
По умолчанию

Не знаю получилось или нет у автора темы, я напишу про результат своего эксперимента.
Похоже что диалоговое окно, которое показывает программа автора, создана при помощи вызова MessageBox, а для кнопок в системных диалогах функция FindWindowEx не работает. Однако эти кнопки можно обнаружить перебором идентификаторов через GetDlgItem(), в принципе, быстро делается.

Сделал первую программу, которая создаёт MessageBox с заголовком 'stddlg' и с кнопками Yes, No, Cancel.
Надо нажать кнопку Yes на ней из другой программы.
Код:
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows,Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
   ret: longint;
begin
  ret := Application.MessageBox( 'ta-ta-ta', 'stddlg', MB_YESNOCANCEL);
  if ret = IDYES
  then begin
       ShowMessage( 'Yes pressed' );
  end
  else begin
       ShowMessage( 'something else pressed' );
  end;

end;

end.
Сделал вторую программу, из которой отправляется сообщения WM_KEYDOWN и WM_KEYUP первой.
Это нажатие на кнопку на диалоге, на которой фокус. В моей программе фокус на кнопке Yes, вот она нажимается, если надо нажать на другую, то надо перед этим отправить сообщение TAB, чтобы перейти на другую кнопку.
Когда передаём сообщение через SendDlgItemMessage(), то там надо указать идентификатор любой кнопки на диалоге, а нажмётся всё равно та, на которой фокус.

Код:
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows, Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);

var
  win1_hdl: hWnd;
  win1_btn_hdl: hWnd;
  ci: longint;
begin
    win1_hdl:=FindWindow( nil, 'stddlg' );
//    ShowMessage( 'win1='+IntToStr( win1_hdl ) );
    if win1_hdl=0
    then begin
      ShowMessage( 'window not found' );
      exit;
    end;

     // находим любую кнопку на стандартном диалоге
      for ci:=0 to 10000000
      do begin
         win1_btn_hdl:=GetDlgItem( win1_hdl, ci );
         if win1_btn_hdl <> 0
         then begin
                break;
         end;
      end;

    if win1_btn_hdl=0
    then begin
      ShowMessage( 'button not found:'+IntToStr( GetLastError() ) );
      exit;
    end;

    SetForegroundWindow( win1_hdl );
    SetActiveWindow( win1_hdl );
    SendDlgItemMessage( win1_hdl, GetDlgCtrlID( win1_btn_hdl ),
                      WM_KEYDOWN, VK_RETURN, 0 );
    SendDlgItemMessage( win1_hdl, GetDlgCtrlID( win1_btn_hdl ),
                      WM_KEYUP, VK_RETURN, 0 );


end;

end.
Изображения
Тип файла: png app1.png (19.3 Кб, 14 просмотров)
DeepFlake вне форума Ответить с цитированием
Старый 07.03.2025, 17:47   #9
cllc
Пользователь
 
Регистрация: 17.01.2020
Сообщений: 14
По умолчанию

Тоже люблю эксперименты. Кнопка в MessageBox находится. На VK_RETURN кнопка не реагирует, а вот на VK_SPACE - очень даже. Даже та, которая не в фокусе. Код для Lazarus:
Код:
program Project1;
{$APPTYPE CONSOLE}
uses Windows, Classes;
type

  { T }

  T = class(TThread)
    procedure Execute; override;
  end;

{ T }

procedure T.Execute;
begin
  case MessageBox(0, 'MB', 'Hello MB', MB_YESNOCANCEL) of
    IDYES: WriteLn('Yes');
    IDNO: WriteLn('No');
    IDCANCEL: WriteLn('Cancel');
  end;
end;
var h: HWND;
begin
  with T.Create(False) do
    FreeOnTerminate:=True;
  Sleep(1000);
  h := FindWindow(nil,'Hello MB');
  h := FindWindowEx(h, 0, nil, PChar(Utf8ToAnsi('&Нет')));
  if h <> 0 then
  begin
    SendMessage(h, WM_KEYDOWN, VK_SPACE, 1 or MapVirtualKey(VK_SPACE, 0) shl 16);
    SendMessage(h, WM_KEYUP, VK_SPACE, 1 or MapVirtualKey(VK_SPACE, 0) shl 16);
  end;
  ReadLn;
end.
cllc вне форума Ответить с цитированием
Старый 07.03.2025, 18:33   #10
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 186
По умолчанию

cllc, какая операционная система?

На Паскале битовое сложение + , а не or.
Почему сдвиг делаете на 16 бит? а в 32-х и 64-х битных системах разве тоже на 16 ?

Последний раз редактировалось DeepFlake; 07.03.2025 в 18:36.
DeepFlake вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Нажать кнопку scroyler Работа с сетью в Delphi 6 24.03.2013 19:05
Нажать кнопку scroyler Работа с сетью в Delphi 0 05.11.2012 11:40
нажать кнопку Screame Microsoft Office Excel 1 30.08.2009 22:20
Нажать кнопку Dron_kss Работа с сетью в Delphi 1 28.03.2009 17:33
Автосатически нажать OK в диалоге eglantier Microsoft Office Excel 2 16.03.2009 16:27