Главная » Delphi » Форматы в буфере обмена (попытка доработки перекодировщика)

0

В принципе, мы теперь знаем путь, на котором можно довести до работоспособности в Windows ХР перекодировщик Layout из главы 5 — можно просто включить в него переключатель раскладки для того приложения, в котором происходит перекодировка. Тогда русский текст должен вставляться нормально. Однако это "лобовое" решение довольно некрасиво — я, например, терпеть не могу никаких автоматических переключателей раскладки. Очевидное решение заключается в том, чтобы как-то разместить в буфере обмена вместе с текстом указание на то, что он русский. Только как это сделать? Вот очень изящный метод специально "для чайников": разместить на форме невидимый RichEdit и "пропустить" текст через него, т. е. вставить туда текст, объявить ему нужный charset и затем снова забрать в буфер методом RichEdit.CopyTodipboard — он сам за вас все сделает. К сожалению, это нам не подходит, т. к. у нас нет формы. Наиболее капитальный метод— разместить в буфере, кроме простого текстового формата, еще и тот же текст в формате RTF— приложение само выберет то, что нужно. Оба этих способа приведены в самой большой, наверное, из существующих, подборке FAQ по Delphi на русском языке [24].

Но совсем зря, что ли, в Windows используется Unicode? Оказывается нет, но размещать в буфере обмена текст только в Unicode следует исключительно для семейства NT— в 9х либо не получите ничего вообще, либо получите полную чушь вплоть до обрушения системы. Поэтому надо либо опять же "городить" свой буфер обмена с множеством форматов, либо усложнять программу и определять, к какому семейству принадлежит установленная Windows. Последнее может дать поле dwPiatformid структуры osversioninfo, которую можно получить через функцию GetVersionEx. В пособии (вы уже, наверное, привыкли, что "пособием" без уточнений я называю официальный сайт [14]), написано, что перед вызовом этой функции надо установить размер структуры (т. к. он, видимо, от версии к версии может различаться). То есть в нашем перекодировщике надо соорудить вот такое условие [19]:

var

Version: TOSVersionlnfo; перекодируем строку>

Version.dwOSVersionlnfoSize := SizeOf(TOSVersionlnfo); GetVersionEx(Version);

if Version.dwPiatformid = VER PLATFORM WIN32 NT then begin

<тут оперируем с Unicode> end else

<тут действуем, как раньше>

Скопируем нашу недоделанную программу Layout из папки Glava5\4 в новую папку (Glava8\4) и приступим к внесению изменений. Установки языка через LoadKeybonrdLayout нам, понятно, здесь больше не понадобятся. Для того чтобы загрузить в буфер обмена строку в формате Unicode (или вообще в каком- нибудь определенном формате), в модуле Clipbrd определен метод setAsHandle (соответствующие методы буфера обмена в Delphi основаны на API-функциях SetClipboardData И GetClipboardData). То есть требуется полу- чить дескриптор строки, для чего мы пойдем стандартным путем: расположим Unieode-строку в куче (heap).

Однако предварительно надо и получить строку из буфера обмена, если она там в Unicode. Это проще— по крайней мере не надо определять версию Windows, следует просто узнать, есть ли среди прочих форматов в буфере формат CF_UNICODETEXT.

Вот как это все можно реализовать. Объявим в программе Layout дополнительные переменные:

var

pstw:PWideChar; stw:Widestring;

stSize, i, n: integer; /размер строки и счетчикиI Version: TOSVersionlnfo; stHdl: THandle; stPtr: Pointer;

Соответствующий фрагмент текста процедуры перекодировки по нажатию горячей клавиши будет выглядеть следующим образом:

Sleep(100); Clipboard.Open;

if Clipboard.HasFormat(CF_UNICODETEXT) then begin

stHdl:Clipboard.GetAsHandle(CFJJNICODETEXT); stPtr:=GlobalLock(stHdl);

pstw:=stPtr; stw:=pstw;

GlobalUnlock(stHdl); stClb:=»stw; end

•1m stClb:=C1ipboard.AsText; {забрали в строку чистый текст) <перекодируем строку>

Version.dwOSVersionlnfoSize := SizeOf(TOSVersionlnfo); GetVersionEx(Version);

if Version.dwPlatformld = VER_PLATFORM_WIN32_NT then begin (это NT) with Clipboard do begin

stSize:=length(stClb)*sizeof(WideChar)+2;

{длина строки в Unicode! stHdl:=GlobalAlloc(GMEM_MOVEABLE,stSize);

{отводим память в куче! stPtr:=GlobalLock(stHdl); (указатель на эту память) MultiByteToWideChar(СР_АСР,0,PChar(stClb),Length(stClb), stPtr,stSize); {преобразуем в Unicode} Clear; {очищаем буфер)

Clipboard.SetAsHandle(CFJJNICODETEXT,stHdl);

(забираем в него} GlobalUnlock(stHdl); GlobalFree(stHdl); {очищаем память} end;

end else {это 9x) Clipboard.AsText:-stClb; Clipboard.Close; <эмулируем нажатие клавиш>

Здесь задержка sleep (l00) необходима, чтобы в Windows ХР приложение, из которого производится копирование, успело закрыть свой буфер обмена — ведь программы выполняются независимо и за время мгновенного перехода от имитации команд копирования к открытию буфера приложение почти гарантированно не успеет этого сделать (если только мы не попадем на самый конец кванта времени, который отводится нашей программе).

Если мы проверим работу зтой программы, то увидим, что, по крайней мере, с Блокнотом все теперь работает правильно, но наблюдаются как конфликты с пресловутым множественным буфером обмена в Word ХР, так и несуразицы с русским языком в некоторых He-Unicode редакторах, о чем шла речь ранее. Чтобы решить оставшиеся проблемы, надо поэкспериментировать с форматами и научиться как-то справляться с Word, но углубляться в эту тему далее мы уже не будем. Для детального изучения есть много ресурсов с более подробным описанием приемов работы с буфером обмена, а сами по себе эти приемы в прикладных программах требуются нечасто — если вы поэкспериментируете, то увидите, что копировать по указанной схеме (без обратной вставки) из Word можно без проблем, а это значительно более распространенная задача.

Источник: Ревнч Ю. В.  Нестандартные приемы программирования на Delphi. — СПб.: БХВ-Петербург, 2005. — 560 е.: ил.

По теме:

  • Комментарии