Отправить CTRL+V в ParentWindow в Delphi с помощью SendMessage

Я пытался отправить нажатия клавиш в окно блокнота в Delphi. Это код, который у меня есть до сих пор:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  windows,
  messages;

var
  H : HWND;

begin
  H := FindWindowA(NIL, 'Untitled - Notepad');
  if H <> 0 then begin
    SendMessage(H, WM_KEYDOWN, VK_CONTROL, 1);
    SendMessage(H, WM_KEYDOWN, MapVirtualKey(ord('v'), 0), 1);
    SendMessage(H, WM_KEYUP, MapVirtualKey(ord('v'), 0), 1);
    SendMessage(H, WM_KEYUP, VK_CONTROL, 1);
  end;
end.

Я также нашел этот пример:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  windows,
  messages;

var
  H : HWND;
  I : Integer;
  s : String;

begin
  h := FindWindowA(NIL, 'Untitled - Notepad');
  if h <> 0 then
  begin
    h := FindWindowEx(h, 0, 'Edit', nil);
    s := 'Hello';
    for i := 1 to Length(s) do
    SendMessage(h, WM_CHAR, Word(s[i]), 0);
    PostMessage(h, WM_KEYDOWN, VK_RETURN, 0);
    PostMessage(h, WM_KEYDOWN, VK_SPACE, 0);
  end;
end.

Как я могу смоделировать/отправить CTRL+V в родительское окно, чтобы оно также работало с другими приложениями? Не каждое приложение имеет те же имена классов и элементы управления, что и блокнот.


person Benjamin Weiss    schedule 08.06.2013    source источник
comment
Знаете ли вы, правильно ли он получает дескриптор? (например, всплывающее сообщение, если ваш if срабатывает)   -  person lurker    schedule 08.06.2013
comment
Почему бы вам не опубликовать WM_PASTE сообщение вместо этого?   -  person TLama    schedule 08.06.2013
comment
Он находит дескриптор окна, и он действителен. Я также пробовал SendMessage(H, WM_PASTE, 0, 0);, но безуспешно.   -  person Benjamin Weiss    schedule 08.06.2013


Ответы (1)


Если вы переключите SendMessage() на PostMessage(), это будет работать:

uses
  Winapi.Windows, Winapi.Messages;

procedure PasteTo(const AHWND: HWND);
begin
  PostMessage(AHWND, WM_PASTE, 0, 0);
end;

var
  notepad_hwnd, notepad_edit_hwnd: HWND;

begin
  notepad_hwnd := FindWindow(nil, 'Untitled - Notepad');
  if notepad_hwnd <> 0 then
  begin
    notepad_edit_hwnd := FindWindowEx(notepad_hwnd, 0, 'Edit', nil);
    if notepad_edit_hwnd <> 0 then
      PasteTo(notepad_edit_hwnd);
  end;
end.

Согласно этой теме, я считаю, что вы не можете использовать SendMessage()/ PostMessage() для отправки состояния модификаторов клавиш (в данном случае CTRL), и что ваш единственный вариант - использовать SendInput(), но это будет работать только в окне, которое в данный момент имеет фокус.

person Marko Paunovic    schedule 08.06.2013
comment
Это сработает, но вам нужен дескриптор управления. Что, если я захочу использовать его в другом приложении, в котором вообще нет класса Edit? Мне нужно было бы найти активное дочернее окно, которое в данный момент сфокусировано, и я не знаю, как это сделать. - person Benjamin Weiss; 08.06.2013
comment
Это другой вопрос. Если приложение, которое вы хотите вставить, в настоящее время имеет фокус, почему бы просто не использовать SendInput()? - person Marko Paunovic; 08.06.2013
comment
В любом случае, вы можете перечислить дочерние окна с помощью EnumChildWindows() API. - person Marko Paunovic; 08.06.2013
comment
Спасибо, это работает! Я также использовал технику AttachThreadInput с этим. - person Benjamin Weiss; 08.06.2013