Работа с буфером обмена |
Как-то раз меня посетила мысль о создании глобального помощника в программировании. Что-то вроде автоматизированной вставки заранее подготовленных кусков кода в буфер обмена. Но этой идее не суждено было стать реальности в связи со смутным представлением о результате, посему проект был заморожен. До того момента я еще ни разу не работал с буфером обмена, поэтому решил разобраться, что тут к чему. Собственно, в данной статье я буду вести разговор не о неудавшихся попытках сделать Всея Искусственный Разум, а как раз о обычной работе с буфером обмена. Буфер обмена может хранить совершенно любые данные, в том числе и пользовательские, но в данной статье я рассмотрю лишь работу с обычным текстом и совсем чуть-чуть расскажу о формате изображений. Для начала рассмотрим процесс чтения обычного текста. Естественно, прежде чем что-то делать с буфером, его необходимо открыть, для этого существует соответствующая функция:
Функция возвращает true, если буфер удалось открыть, и false в случае ошибки. Ну и, после того как работа с буфером будет закончена, необходимо его закрыть, это действие выполняет функция:
Если буфер успешно закрыт, то функция возвращает true, иначе false. Итак, следующим шагом является проверка буфера на наличие какой-либо информации. Для этого нужно прощупать буфер специальной функцией, с желаемыми параметрами:
В случае успеха функция возвращает идентификатор блока памяти, в котором содержатся сами данные, в противном случае возвращает 0. Иными словами, если данные запрашиваемого типа имеются в буфере, то функция завершается успешно. Параметр uFormat , при запросе обычного текста должен принимать значение CF_TEXT. На самом деле текстовых форматов несколько, например тексту в OEM кодировке соответствует константа CF_OEMTEXT, но рассматривать их в данной статье мы не будем. Теперь, если идентификатор не равен нулю, то есть все нормально, нужно узнать размер блока памяти, для этого существует функция:
Возвращаемое значение и будет размером блока памяти. Переходим к самому интересному - к чтению данных. Надо отметить, что данные можно считывать, используя идентификатор блока памяти в качестве указателя, но так делать не рекомендуется. Сейчас нужно получить указатель на блок данных и для этого есть соответствующая функция, которая, кроме того что возвращает указатель на данные, еще и фиксирует блок в памяти:
И теперь, остается только скопировать данные куда-нибудь, с помощью например memcpy, где в качестве второго параметра использовать указатель возвращенный функцией GlobalLock, а в качестве третьего - размер блока, полученный с помощью функции GlobalSize. Думаю, о первом параметре говорить не нужно. После этого нужно разблокировать блок памяти функцией:
В самом конце закрыть буфер функцией, уже описанной выше, CloseClipboard. В случае же с записью данных в буфер порядок следования вызовов функций OpenClipboard и CloseClipboard остается неизменным. Вообще, прежде чем писать что-либо в буфер, его нужно очистить.
Функция возвращает true если буфер успешно очищен и else в случае ошибки. Для того чтобы записать данные в буфер нужно сначала выделить блок памяти, а потом передать идентификатор блока в качестве параметра соответствующей функции. Выделить блок памяти можно функцией GlobalAlloc.
Атрибуты указывают способ выделения памяти, например, если нужно заполнить ее нулями, то следует использовать флаг GMEM_ZEROINIT. Но достаточно просто выделить фиксированный блок памяти, с помощью флага GMEM_FIXED. Следует отметить, что константа GMEM_FIXED равна 0. Этим я воспользовался при написании примера к данной статье, где в качестве параметра передавал значение NULL. Вообще же, при фиксированном блоке памяти, вызов функции GlobalLock нужен скорее в эстетических целях, для получения указателя на блок. Далее нужно скопировать данные с помощью все той же memcpy. Логично предположить, что раз есть функция GetClipboardData, то есть и функция SetClipboardData, такое предположение, в данном случае, верно.
Формат нужно указать текстовый - CF_TEXT, а в качестве handle передать идентификатор блока выделенной памяти. Это был простейший случай работы с буфером обмена, на примере обычного текста. Но этой информации должно хватить для понятия основных принципов. Я не буду вдаваться в подробности считывания и записи изображений, алгоритм тот же что и с текстом, скажу лишь, что формат изображений CF_DIB. По сути это обычный bmp файл, но без самого первого заголовка. У bmp файла есть два заголовка BmpHeader и BmpInfoHeader, подробнее можно посмотреть в файле Image.h, в прилагаемом к статье архиву. Так вот, данные в формате CF_DIB начинаются с BmpInfoHeader и идут до последнего байта картинки, поэтому первый заголовок придется писать вручную. Вообще данная информация является неполной и может быть даже ошибочна, ибо получена методом тыка, но это работает. А теперь немного о прилагающейся программе и исходниках. При нажатии комбинации Ctrl + 1 на экран выводится текстовая информация, из буфера, если таковая имеется. При нажатии комбинации Ctrl + 2 буфер заполняется текстовой строкой «Hello Clipboard!». При нажатии комбинации Ctrl + 3 в файл, с именем «Image.bmp», сохраняется картинка из буфера обмена, если она там есть. И, наконец, при нажатии комбинации Ctrl + 4 в буфер записывается картинка из файла «Grey.bmp», который поставляется с архивом. На этом все. Скачать программу и исходный код к статье можно З Д Е С Ь |
|