Столкнулся с проблемой неправильной кодировки при переносе данных из приложений на Delphi.
Если переключить раскладку на РУС, то работа с буфером идёт корректно, иначе кракозябры.
По сети есть несколько решений:
Суть состоит в том, чтобы реализовать исправления в буфере динамически для всех текстовых сообщений направляемых в буфер.
Сразу же добавим в раздел uses модуль Clipbrd, в котором объявлены функции.
В Delphi нет готового обработчика события, который мог бы отвечать на изменения буфера обмена, поэтому придется описать самостоятельно. Для этого в разделе private главной формы пишем следующий код:
Процедура WMChangeCBChain является обработчиком системного события WM_CHANGECBCHAIN. Об этом говорит добавленный в конце объявления процедуры оператор message с названием системного события. Это событие генерируется каждый раз, когда изменяется очередь, а именно происходит удаление или добавление какого-то наблюдателя. Чуть позже мы рассмотрим наши действия, которые должны быть в этом обработчике. Процедура WMDrawClipboard будет обработчиком системного события WM_DRAWCLIPBOARD. Оно генерируется каждый раз, когда в буфере обмена изменились данные, и его нужно перерисовать.
Активизировать наблюдатель можно в любом событии, лучше сразу при создании формы.
Теперь посмортим на реализацию функции WMChangeCBChain, котороая вызывается при изменении очереди наблюдателей за буфером обмена:
В качестве параметра функции мы получаем переменную Msg типа структуры TWMChangeCBChain. В этой структуре нас будут интересовать два свойства: Remove и Next. Первое свойство указывает а окно, которое должно быть удалено из очереди, а второе указывает на окно, следующее за ним. Наша задача проверить, если удаляемое окно является удаляемым, которому мы посылаем сообщения, то должна быть произведена замена следующим наблюдателем.
Таким образом любые текстовые данные перемещаемые из приложения (любого приложения в момент работы программы) через буфер, будут преобразованы в UNICODE и правильно поняты приложением-приемником.
Если переключить раскладку на РУС, то работа с буфером идёт корректно, иначе кракозябры.
По сети есть несколько решений:
- Использовать набор компонентов Unicode от TMS Software ("+" Быстро для старта / "-" Платные)
- Использовать модуль RusClipboard.pas
- Использовать процедуру правильно для правильного формирования сообщений буферу. SQL.RU ( "-" Ручное формирование буфера обмена)
Суть состоит в том, чтобы реализовать исправления в буфере динамически для всех текстовых сообщений направляемых в буфер.
Сразу же добавим в раздел uses модуль Clipbrd, в котором объявлены функции.
В Delphi нет готового обработчика события, который мог бы отвечать на изменения буфера обмена, поэтому придется описать самостоятельно. Для этого в разделе private главной формы пишем следующий код:
uses
Windows,Clipbrd;
private
{ Private declarations }
FNextViewer:HWnd;
procedure WMChangeCBChain(var Msg: TWMChangeCBChain); message WM_CHANGECBCHAIN;
procedure WMDrawClipboard(var Msg: TWMDrawClipboard); message WM_DRAWCLIPBOARD;
publicЗдесь у нас объявлена переменная FNextViewer типа HWnd, в которой будем хранить указатель на следующее в системе окно, зарегистрированное в качестве наблюдателя.
{ Public declarations }
Процедура WMChangeCBChain является обработчиком системного события WM_CHANGECBCHAIN. Об этом говорит добавленный в конце объявления процедуры оператор message с названием системного события. Это событие генерируется каждый раз, когда изменяется очередь, а именно происходит удаление или добавление какого-то наблюдателя. Чуть позже мы рассмотрим наши действия, которые должны быть в этом обработчике. Процедура WMDrawClipboard будет обработчиком системного события WM_DRAWCLIPBOARD. Оно генерируется каждый раз, когда в буфере обмена изменились данные, и его нужно перерисовать.
Активизировать наблюдатель можно в любом событии, лучше сразу при создании формы.
procedure Tform1.FormCreate(Sender: Tobject);
begin
FnextViewer:=SetClipboardViewer(Handle);
end;
Функция SetClipboardViewer получает в качестве параметра идентификатор окна, которое регистрируется как наблюдатель за буфером обмена. Именно этому окну будут направляться сообщения WM_CHANGECBCHAIN и WM_DRAWCLIPBOARD, и вы должны реализовать корректные обработчики событий. В качестве результата функция возвращает идентификатор окна, следующего за вашим в цепочке наблюдателей. После обработки события вы должгы сообзить этому окну о том, что в буфере произошли изменения, т.е. передать событие по цепочке.Теперь посмортим на реализацию функции WMChangeCBChain, котороая вызывается при изменении очереди наблюдателей за буфером обмена:
procedure Tform1.WMChain(var Msg: TWMChangeCBChain);
begin
if Msg.Remove = FNextViewer then
FnextViewer:=Msg.Next
else
SendMessage(FNextViewer, WM_CHANGECBCHAIN, Msg.Remove, Msg.Next);
end;
В качестве параметра функции мы получаем переменную Msg типа структуры TWMChangeCBChain. В этой структуре нас будут интересовать два свойства: Remove и Next. Первое свойство указывает а окно, которое должно быть удалено из очереди, а второе указывает на окно, следующее за ним. Наша задача проверить, если удаляемое окно является удаляемым, которому мы посылаем сообщения, то должна быть произведена замена следующим наблюдателем.
procedure TForm1.WMDrawClipboard(var Msg: TWMDrawClipboard);Эта процедура срабатывает на изменение буфера обмена. В переменную WideBuffer помещается текущее содержание буфера (только если его содержимое - текст), далее рассчитывается размер и содержимое переменной перемещается в буфер в формате UNICODE.
var WideBuffer: WideString;
BuffSize: Cardinal;
Data: THandle;
DataPtr: Pointer;
begin
WideBuffer := clipboard.AsText;
BuffSize := length(WideBuffer) * SizeOf(WideChar);
Data := GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE+GMEM_ZEROINIT, BuffSize + 2);
try
DataPtr := GlobalLock(Data);
try
Move(PWideChar(WideBuffer)^, Pointer(Cardinal(DataPtr))^, BuffSize);
finally
GlobalUnlock(Data);
end;
Clipboard.SetAsHandle(CF_UNICODETEXT, Data);
except
GlobalFree(Data);
raise;
end;
end;
Таким образом любые текстовые данные перемещаемые из приложения (любого приложения в момент работы программы) через буфер, будут преобразованы в UNICODE и правильно поняты приложением-приемником.
ОГРОМНОЕ СПАСИБО! Работает а Delphi 7.
ОтветитьУдалитьНе работает
ОтветитьУдалитьЭта разрабатывалась под win7, возможно на Win10 уже не работает. Попробуйте поставить отладочные ShowMessage на события чтения буфера и после формирования декодированной строки.
Удалить