Selukwe Ответов: 2

Как запретить другим программам отслеживать измененный буфер обмена


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

Я нашел этот код, который должен был сделать трюк, но он этого не делает (в Win 10 Ent x64). Есть ли в этом коде какая-то ошибка, которую можно исправить?

Файл pas следующим образом:

(* ---------------------------------------------------------------
 { TAntiClipboardLogging }
Generates OnClipboardChange event when contents of clipboard
changes. Property PreventClipboardLogging to toggle ClipboardLogging
on or off.

Sample code usage:
==================

  private
    { Private declarations }
    FBlocker: TAntiClipboardLogging; // for anti-Clipboard logging

procedure TFormMain.StartAntiClipboardLoggingProc;
begin
  // start anti-Clipboard logging
  FBlocker := TAntiClipboardLogging.Create;
  FBlocker.PreventClipboardLogging := True;
  Application.ProcessMessages;
end;

procedure TFormMain.StopAntiClipboardLoggingProc;
begin
  // stop anti-Clipboard logging
  FBlocker.PreventClipboardLogging := False;
  FBlocker.Free;
  Application.ProcessMessages;
  Sleep(100); // e.g. if clearing Clipboard afterwards
end;
---------------------------------------------------------------- *)
unit AntiClipboardLogging;

interface

uses
  Windows, Messages, Classes;

type
  TClipboardChangeEvent = TNotifyEvent;

  { TClipboardActivityMonitor }
  TClipboardActivityMonitor = class(TPersistent)
  private
    FMonitorWindow: THandle;
    FNextWindow: THandle;
    FPreventClipboardLogging: Boolean;
    FOnClipboardChange: TClipboardChangeEvent;
    procedure PassMessage(Message: TMessage);
    procedure SetPreventClipboardLogging(const Value: Boolean);
  protected
    procedure DoClipboardChange; virtual;
    procedure WndProc(var Message: TMessage); virtual;
    property OnClipboardChange: TClipboardChangeEvent
      read FOnClipboardChange write FOnClipboardChange;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    property PreventClipboardLogging: Boolean
      read FPreventClipboardLogging write
      SetPreventClipboardLogging;
  end;

  TAntiClipboardLogging = class(TClipboardActivityMonitor)
  published
    property OnClipboardChange;
    property PreventClipboardLogging;
  end;

implementation

uses
  Forms;

{ TClipboardActivityMonitor }

constructor TClipboardActivityMonitor.Create;
begin
  FPreventClipboardLogging := False;
end;

destructor TClipboardActivityMonitor.Destroy;
begin
  SetPreventClipboardLogging(False);
  inherited;
end;

procedure TClipboardActivityMonitor.DoClipboardChange;
begin
  if Assigned(FOnClipboardChange) then
    FOnClipboardChange(Self);
end;

procedure TClipboardActivityMonitor.PassMessage(Message: TMessage);
begin
  SendMessage(FNextWindow, Message.Msg, Message.WParam,
    Message.LParam);
end;

procedure TClipboardActivityMonitor.SetPreventClipboardLogging(const
  Value: Boolean);
begin
  if FPreventClipboardLogging = Value then
    Exit;
  if Value then
    begin
      FMonitorWindow := AllocateHWnd(WndProc);
      FNextWindow := SetClipBoardViewer(FMonitorWindow);
    end
  else
    begin
      ChangeClipboardChain(FMonitorWindow, FNextWindow);
      DeallocateHWnd(FMonitorWindow);
    end;
  FPreventClipboardLogging := Value;
end;

procedure TClipboardActivityMonitor.WndProc(var Message: TMessage);
begin
  if Message.Msg = WM_DRAWCLIPBOARD then
    begin
      // This Message is also triggered when starting
      // or stopping to monitor
      // In these cases Clipboard.FormatCount will always
      // return 0 (??)
      try
        DoClipboardChange;
      finally
      // PassMessage(Message); // Remove this line to break chain
      end;
    end;

  //wParam = HWNDRemove
  //lParam = HWNDNext
  if Message.Msg = WM_CHANGECBCHAIN then
    begin
      // If next window is the one to be removed, LParam is
      // the new NextWindow.
      // Else pass the message to our NextWindow
      if FNextWindow = Cardinal(Message.WParam) then
        FNextWindow := Cardinal(Message.LParam)
      else
        PassMessage(Message);
    end;

  with Message do
    Result := DefWindowProc(FMonitorWindow, Msg, wParam, lParam);
end;

end.


Что я уже пробовал:

Приведенный выше код, но он не работает.

2 Ответов

Рейтинг:
2

Jochen Arndt

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

Но у этого решения есть три недостатка:

  1. Буфер обмена может быть доступен любому приложению в любое время
  2. Приложения, которые находятся в цепочке до вашего приложения, все еще получают уведомления
  3. Большинство приложений даже не использовали цепочку буфера обмена

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


Selukwe

Спасибо, Йохен. Вы, кажется, поняли мою точку зрения и, похоже, хорошо разбираетесь в механизме буфера обмена. Итак, подводя итог - есть ли обходной путь, чтобы сделать эту работу? Я после вставки из буфера обмена некоторого текста, который в течение нескольких секунд не должен быть извлечен из буфера обмена другими приложениями. Можно ли это сделать?

Jochen Arndt

Нет никакого реального решения. Как только что-то было помещено в буфер обмена, оно становится доступным для всех других приложений.

То, что вы можете сделать, это получить все данные из буфера обмена в локальное хранилище, очистить буфер обмена и поместить данные обратно через некоторое время.

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

Jochen Arndt

Это называется IPC (Inter Process Communication). Существует несколько методов реализации таких как сокеты на локальном хосте или общая память, но обе стороны должны использовать один и тот же метод и знать, как обрабатывать данные (использовать один и тот же протокол).

Selukwe

Это мне не пригодится. Я ищу возможность передавать строки в обычные сторонние программы, которые я не могу контролировать.

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

Jochen Arndt

Любое окно, которое зарегистрировалось как цель перетаскивания, будет уведомлено, когда курсор мыши войдет, переместится или покинет окно во время перетаскивания. С помощью уведомлений такие окна имеют полный доступ к перетаскиваемым данным.

Selukwe

Итак, что бы вы порекомендовали в качестве наиболее безопасного способа передачи текстовых строк/данных между приложениями, когда местом назначения является стороннее приложение?

Jochen Arndt

Это зависит от методов, предоставляемых целевым приложением.

Selukwe

Не могли бы Вы уточнить, какой путь исследовать? Целевым приложением является веб-браузер, программа MS Office, Блокнот, любое стандартное коммерческое программное обеспечение...

Jochen Arndt

Я не могу быть конкретным, потому что ваш список приложений слишком широк.

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

Общего решения для таких задач не существует, потому что общее решение всегда будет самым небезопасным, как буфер обмена.

Я все еще не могу понять, чего ты хочешь добиться.

Если вы хотите передать конфиденциальную информацию, например пароль:
Не делайте этого и не говорите пользователю ясно, что ваше приложение делает это и что данные могут быть обнюханы. Затем пользователь несет ответственность за то, чтобы не было установлено никаких программ обнюхивания (что всегда происходит, потому что данные могут быть обнюханы многими методами).

Selukwe

Спасибо, Йохен. Да, это может быть пароль, данные для входа в систему или короткий текст, хранящийся в зашифрованном виде. Находясь внутри, он может считаться безопасным, и я просто хотел убедиться, что когда он "выходит", он также безопасен, насколько это возможно. Оказывается, на самом деле это не так уж и возможно...-?

Jochen Arndt

Если данные зашифрованы, вам должно быть все равно.

Но данные принадлежат Пользователю, так что у него есть доступ. И так же есть приложения, установленные и запущенные пользователем. Если он установил приложение, которое обнюхивает буфер обмена для получения конфиденциальной информации, это приложение, вероятно, также будет обнюхивать в другом месте, например, подключая ввод с клавиатуры и выполняя сканирование памяти.

И эта информация также должна быть передана в ваше приложение изначально, чтобы приложение-Нюхач уже могло иметь эти данные.

Selukwe

Спасибо, Йохен. Вы мне очень помогли:)

Рейтинг:
0

OriginalGriff

Насколько я знаю, вы не можете запретить любому приложению - не говоря уже обо всех - получить доступ к буферу обмена в любое время. Это своего рода точка зрения - буфер обмена является областью обмена данными для пользователя, а не для приложений.

Если вы используете буфер обмена в качестве межпроцессного канала связи, вы будете раздражать чертовски "обычных пользователей", которые хотят, чтобы то, что они скопировали там. Вероятно, вам следует изменить дизайн, чтобы использовать сокеты вместо буфера обмена - он будет более надежным, более безопасным и не будет раздражать ваших пользователей!


Selukwe

Спасибо. Я не хочу блокировать буфер обмена. Речь не идет о предотвращении доступа приложений к буферу обмена. Я знаю, что это невозможно. Но если я правильно понял, измененный буфер обмена отправляет сообщение другим приложениям, информируя их об изменении. То, что мне нужно, - это временно прервать эту цепочку сообщений, чтобы другие приложения не заметили измененного содержимого буфера обмена. Но это содержимое все равно будет там и доступно при вставке действия - как по щелчку правой кнопкой мыши меню, так и по сочетанию клавиш.

Код, который я представил, хорошо работал в Win XP, и я думаю, что также в Win 7, но не работает в Win 10. Поэтому я ищу квалифицированного эксперта по Delphi, чтобы посоветовать возможный обходной путь в последней среде Windows. Есть ли работоспособный образец использования сокетов для этой цели?