Контроль за изменением содержимого буфера обмена.

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Контроль за изменением содержимого буфера обмена.

Сообщение Andrey » 04.10.2012 04:16:15

Здравствуйте.
Уже долгое время пытаюсь перевести код из Delphi в Lazarus.
Решил обратится за помощью на форум.
Дело в следующем.
Есть форма Form1, в ней компонент Memo1.
При каждом копировании текстовой информации, например из строки браузера,
в Memo1 в новую строку должно добавлятся содержимое буфера обмена.
В делфи для этой цели я использовал следующий код, который выпытал методом поисков и ошибок на форуме:
http://www.delphimaster.ru/cgi-bin/foru ... 70409&n=18

Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Clipbrd;

type

  { TForm1 }

  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
    HandleNext: HWND;
procedure OnDrawClipboard(var msg: TWMDrawClipboard);
message WM_DRAWCLIPBOARD;
procedure OnChangeCBChain(var msg: TWMChangeCBChain);
message WM_CHANGECBCHAIN;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
HandleNext:= SetClipboardViewer(Handle);
end;


procedure TForm1.OnDrawClipboard(var msg: TWMDrawClipboard);
begin
if Clipboard.HasFormat(CF_TEXT) then
   Memo1.Lines.Add(Clipboard.AsText);
inherited
end;


procedure TForm1.OnChangeCBChain(var msg: TWMChangeCBChain);
begin
if msg.Remove = HandleNext then
   HandleNext := msg.Next;
inherited
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain (Handle, HandleNext);
end;

end.


При попытке использовать данный код в Lazarus
Наткнулся на то, что компилятор выдал несколько ошибок.
unit1.pas(22,52)Error: Identifier not found "TWMDrawClipboard"
unit1.pas(24,52)Error: Identifier not found "TWMChangeCBChain"
unit1.pas(33,1)Fatal: There were 2 errors compiling module, stopping

Не зная как исправить ошибки продолжил поиск и
наткнулся на сайт http://www.drkb.ru/ где в справке drkb3.chm нашёл похожий код,но тоже для Delphi.

Код: Выделить всё
unit Unit1;

{©Drkb v.3(2007): www.drkb.ru}

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls;

type

TForm1 = class(TForm)

   Memo1: TMemo;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);

private

   hwndNextViewer: THandle;
   procedure WMChangeCbChain(var Message: TWMChangeCBChain); message WM_CHANGECBCHAIN;
   procedure WMDrawClipboard(var Message: TMessage); message WM_DRAWCLIPBOARD;

end;

var

Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);

begin
// Добавляем наше окно в цепочку
// зарегистрированных наблюдателей буффера обмена
hwndNextViewer := SetClipboardViewer(Handle);
Memo1.Lines.Clear
end;



procedure TForm1.WMChangeCbChain(var Message: TWMChangeCBChain);

begin
with Message do
begin
                 // If the next window is closing, repair the chain.
   if Remove = hwndNextViewer then
     hwndNextViewer := Next
                  // Otherwise, pass the message to the next link.
   else
     if hwndNextViewer <> 0 then
       SendMessage(hwndNextViewer, Msg, Remove, Next);
end;
end;



            // clipboard contents changed.

procedure TForm1.WMDrawClipboard(var Message: TMessage);
begin
           // Pass the message to the next window in clipboard
           // viewer chain.
Memo1.Lines.Add('Сhanged');
with Message do
   SendMessage(hwndNextViewer, Msg, WParam, LParam);
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain(Handle, hwndNextViewer);
end;

end.


Во время компиляции этого кода в Lazarus
получается ошибка: Unit.pas(22,58) Error:Identifier not found "TWMChangeCBChain"

Решил заменить везде (var Message: TWMChangeCBChain); на (var Message: TMessage);

Компилирую опять. Теперь компилятор останавливается и выдаёт 3 ошибки.

unit1.pas(53,13) Error:Identifier not found Remove
unit1.pas(56,24) Error:Incompatible types: got "untyped" expected "QWord"
unit1.pas(58,43) Error:Identifier not found Remove

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

В поисках решения нашёл также ссылки:
http://forum.lazarus.freepascal.org/ind ... ic=15488.0
http://forum.sources.ru/index.php?showtopic=91342

Прошу помочь.
Думаю, что и в первом варианте кода возможно изменить этот код для Lazarus.
Andrey
новенький
 
Сообщения: 13
Зарегистрирован: 13.09.2012 22:54:48

Re: Контроль за изменением содержимого буфера обмена.

Сообщение B4rr4cuda » 04.10.2012 22:12:28

Andrey писал(а):TWMChangeCBChain

Выдрать описание этого типа из делфи и определить в начале модуля не пробовали?
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35

Re: Контроль за изменением содержимого буфера обмена.

Сообщение InnI » 05.10.2012 15:23:17

Не так всё просто в Lazarus с обработкой сообщений Windows. Вот рабочий код для отслеживания буфера обмена.
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

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

type
  TFormViewer = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
    procedure WMDrawClipboard;
    procedure WMChangeCBChain(wParam: WParam; lParam: LParam);
  public
    { public declarations }
  end;

var
  FormViewer: TFormViewer;
  PrevWndProc: WNDPROC;
  NextViewer: hWnd;

implementation

{$R *.lfm}

function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
begin
  if uMsg = WM_DRAWCLIPBOARD then FormViewer.WMDrawClipboard;
  if uMsg = WM_CHANGECBCHAIN then FormViewer.WMChangeCBChain(wParam, lParam);
  result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, wParam, lParam);
end;

procedure TFormViewer.FormCreate(Sender: TObject);
begin
  PrevWndProc := Windows.WNDPROC(SetWindowLong(Handle, GWL_WNDPROC, PtrInt(@WndCallback)));
  NextViewer := SetClipboardViewer(Handle);
end;

procedure TFormViewer.FormDestroy(Sender: TObject);
begin
  ChangeClipboardChain(Handle, NextViewer)
end;

procedure TFormViewer.WMDrawClipboard;
begin
  Sleep(150);
  Memo1.Lines.Add(Clipboard.AsText);
  SendMessage(NextViewer, WM_DRAWCLIPBOARD, 0, 0);
end;

procedure TFormViewer.WMChangeCBChain(wParam: WParam; lParam: LParam);
begin
  if wParam = NextViewer
  then NextViewer := lParam
  else SendMessage(NextViewer, WM_CHANGECBCHAIN, wParam, lParam);
end;

end.
InnI
незнакомец
 
Сообщения: 5
Зарегистрирован: 30.11.2011 12:23:30

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Ism » 05.10.2012 16:36:04

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

Там есть примеры работы с буфером , в том числе и проверка изменения
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Ism
энтузиаст
 
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Andrey » 06.10.2012 05:08:54

Благодарю за советы.
Во время компиляции кода предложенного InnI
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

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

type

  { TForm1 }

  TFormViewer = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
    procedure WMDrawClipboard;
    procedure WMChangeCBChain(wParam: WParam; lParam: LParam);
  public
    { public declarations }
  end;

var
  FormViewer: TFormViewer;
  PrevWndProc: WNDPROC;
  NextViewer: hWnd;

implementation

{$R *.lfm}
function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
begin
  if uMsg = WM_DRAWCLIPBOARD then FormViewer.WMDrawClipboard;
  if uMsg = WM_CHANGECBCHAIN then FormViewer.WMChangeCBChain(wParam, lParam);
  result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, wParam, lParam);
end;

{ TForm1 }

procedure TFormViewer.FormCreate(Sender: TObject);
begin
   PrevWndProc := Windows.WNDPROC(SetWindowLong(Handle, GWL_WNDPROC, PtrInt(@WndCallback)));
  NextViewer := SetClipboardViewer(Handle);
end;

procedure TFormViewer.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain(Handle, NextViewer)
end;

procedure TFormViewer.WMDrawClipboard;
begin
  Sleep(150);
  Memo1.Lines.Add(Clipboard.AsText);
  SendMessage(NextViewer, WM_DRAWCLIPBOARD, 0, 0);
end;

procedure TFormViewer.WMChangeCBChain(wParam: WParam; lParam: LParam);
begin
  if wParam = NextViewer
  then NextViewer := lParam
  else SendMessage(NextViewer, WM_CHANGECBCHAIN, wParam, lParam);
end;

end.
   

Происходит остановка компилятора на строке
Код: Выделить всё
   PrevWndProc := Windows.WNDPROC(SetWindowLong(Handle, GWL_WNDPROC, PtrInt(@WndCallback)));

при этом выделяется вся строка а
Код: Выделить всё
Windows
остаётся не выделенным,
и указываются такие ошибки:
unit1.pas(46,70) Hint: Conversion between ordinals and pointers is not portable
unit1.pas(46,19) Error: Illegal type conversion: "LongInt" to "<procedure variable type of function(QWord,LongWord,Int64,Int64):Int64;StdCall>"
unit1.pas(71) Fatal: There were 1 errors compiling module, stopping

Что то не так.
Я делал так: Файл-создать-приложение.
На форму Form1 добавил Memo1.
В инспекторе обьектов в Form1 активировал двойным кликом события FormCreate и FormDestroy.
В начале кода вручную в
Код: Выделить всё
uses
дописал
Код: Выделить всё
Windows, Clipbrd;

Вписал остальной код.
Запустил компилятор, и вот такие ошибки получились.
Где то видимо надо с этим
Код: Выделить всё
Windows
что то сделать. Не знаю что ещё с этим кодом сделать.
Что можете посоветовать ?

ОС Windows 7-64 bit, lazarus-1.0-fpc-2.6.0-win64
Последний раз редактировалось Andrey 06.10.2012 17:48:47, всего редактировалось 1 раз.
Andrey
новенький
 
Сообщения: 13
Зарегистрирован: 13.09.2012 22:54:48

Re: Контроль за изменением содержимого буфера обмена.

Сообщение InnI » 06.10.2012 13:57:59

Нет возможности проверить на х64 :( Попробуйте так:
Код: Выделить всё
PrevWndProc := Windows.WNDPROC(SetWindowLong(Handle, GWL_WNDPROC, Int64(@WndCallback)));
InnI
незнакомец
 
Сообщения: 5
Зарегистрирован: 30.11.2011 12:23:30

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Andrey » 06.10.2012 17:20:32

Поставил
Код: Выделить всё
PrevWndProc := Windows.WNDPROC(SetWindowLong(Handle, GWL_WNDPROC, Int64(@WndCallback)));

Выдаёт те же ошибки.
unit1.pas(46,69) Hint: Conversion between ordinals and pointers is not portable
unit1.pas(46,18) Error: Illegal type conversion: "LongInt" to "<procedure variable type of function(QWord,LongWord,Int64,Int64):Int64;StdCall>"
unit1.pas(71) Fatal: There were 1 errors compiling module, stopping
и слово
Код: Выделить всё
Windows
в
Код: Выделить всё
uses
и в строке которую поменял опять выделяет как и прежде.
Andrey
новенький
 
Сообщения: 13
Зарегистрирован: 13.09.2012 22:54:48

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Mr.Smart » 06.10.2012 17:34:39

Для передачи указателя пользуйтесь функцией SetWindowLongPtr
Код: Выделить всё
PrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Handle, GWL_WNDPROC, @WndCallback));
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Andrey » 06.10.2012 19:20:36

Поставил
Код: Выделить всё
PrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Handle, GWL_WNDPROC, Int64(@WndCallback)));

Всё заработало.
Правда компилятор первый раз выдал:
unit1.pas(46,72) Hint: Conversion between ordinals and pointers is not portable
unit1.pas(46,18) Hint: Conversion between ordinals and pointers is not portable
Проект "project1" успешно собран.
Что переводится как:
unit1.Намек первенства(46,72) : Конверсия между порядковыми номерами и указателями не портативна
unit1.Намек первенства(46,18) : Конверсия между порядковыми номерами и указателями не портативна
При последующих компиляциях никаких сообщений не было.

Не знаю правда что это означает.Но наверно это не самое важное. Главное что программа заработала.
Благодарю всех кто отликнулся за помощь.
Вот код:
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

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

type

  { TForm1 }

  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
    procedure WMDrawClipboard;
    procedure WMChangeCBChain(wParam: WParam; lParam: LParam);
  public
    { public declarations }
  end;

var
  Form1: TForm1;
  PrevWndProc: WNDPROC;
  NextViewer: hWnd;

implementation

{$R *.lfm}
function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
begin
  if uMsg = WM_DRAWCLIPBOARD then Form1.WMDrawClipboard;
  if uMsg = WM_CHANGECBCHAIN then Form1.WMChangeCBChain(wParam, lParam);
  result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, wParam, lParam);
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  PrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Handle, GWL_WNDPROC, PtrInt(@WndCallback)));
  NextViewer := SetClipboardViewer(Handle);
  Memo1.Lines.Clear;
end;

procedure TForm1.WMDrawClipboard;
begin
   Memo1.Lines.Add(Clipboard.AsText);
  SendMessage(NextViewer, WM_DRAWCLIPBOARD, 0, 0);
end;

procedure TForm1.WMChangeCBChain(wParam: WParam; lParam: LParam);
begin
if wParam = NextViewer
then NextViewer := lParam
else SendMessage(NextViewer, WM_CHANGECBCHAIN, wParam, lParam);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
ChangeClipboardChain(Handle, NextViewer)
end;

end.   
Последний раз редактировалось Andrey 06.10.2012 20:48:40, всего редактировалось 1 раз.
Andrey
новенький
 
Сообщения: 13
Зарегистрирован: 13.09.2012 22:54:48

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Mr.Smart » 06.10.2012 20:12:51

Замените Int64 на PtrInt. Это будет идеологически правильней.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Контроль за изменением содержимого буфера обмена.

Сообщение Andrey » 06.10.2012 20:46:36

Хорошо.Заменил.
Andrey
новенький
 
Сообщения: 13
Зарегистрирован: 13.09.2012 22:54:48


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 213

Рейтинг@Mail.ru