Статистика |
|
|
Работа с буфером обмена
Буфер обмена может хранить совершенно любые данные, в том числе и пользовательские, но в данной статье я рассмотрю лишь работу с обычным текстом и совсем чуть-чуть расскажу о формате изображений. Для начала рассмотрим процесс чтения обычного текста. Естественно, прежде чем что-то делать с буфером, его необходимо открыть, для этого существует соответствующая функция:
bool OpenClipboard ( HWND hwnd // Идентификатор окна );
Функция возвращает true, если буфер удалось открыть, и false в случае ошибки. Ну и, после того как работа с буфером будет закончена, необходимо его закрыть, это действие выполняет функция:
bool CloseClipboard ( void );
Если буфер успешно закрыт, то функция возвращает true, иначе false. Итак, следующим шагом является проверка буфера на наличие какой-либо информации. Для этого нужно прощупать буфер специальной функцией, с желаемыми параметрами:
HANDLE GetClipboardData ( UINT uFormat // Формат запрашиваемых данных );
В случае успеха функция возвращает идентификатор блока памяти, в котором содержатся сами данные, в противном случае возвращает 0. Иными словами, если данные запрашиваемого типа имеются в буфере, то функция завершается успешно. Параметр uFormat , при запросе обычного текста должен принимать значение CF_TEXT. На самом деле текстовых форматов несколько, например тексту в OEM кодировке соответствует константа CF_OEMTEXT, но рассматривать их в данной статье мы не будем. Теперь, если идентификатор не равен нулю, то есть все нормально, нужно узнать размер блока памяти, для этого существует функция:
UINT GlobalSize ( HANDLE handle // Идентификатор блока памяти );
Возвращаемое значение и будет размером блока памяти. Переходим к самому интересному - к чтению данных. Надо отметить, что данные можно считывать, используя идентификатор блока памяти в качестве указателя, но так делать не рекомендуется. Сейчас нужно получить указатель на блок данных и для этого есть соответствующая функция, которая, кроме того что возвращает указатель на данные, еще и фиксирует блок в памяти:
LPVOID GlobalLock ( // Тип LPVOID эквивалентен void * HANDLE handle // Идентификатор блока памяти );
И теперь, остается только скопировать данные куда-нибудь, с помощью например memcpy, где в качестве второго параметра использовать указатель возвращенный функцией GlobalLock, а в качестве третьего - размер блока, полученный с помощью функции GlobalSize. Думаю, о первом параметре говорить не нужно. После этого нужно разблокировать блок памяти функцией:
BOOL GlobalUnLock ( HANDLE handle // Идентификатор блока памяти );
В самом конце закрыть буфер функцией, уже описанной выше, CloseClipboard. В случае же с записью данных в буфер порядок следования вызовов функций OpenClipboard и CloseClipboard остается неизменным. Вообще, прежде чем писать что-либо в буфер, его нужно очистить.
BOOL EmptyClipboard ( void );
Функция возвращает true если буфер успешно очищен и else в случае ошибки. Для того чтобы записать данные в буфер нужно сначала выделить блок памяти, а потом передать идентификатор блока в качестве параметра соответствующей функции. Выделить блок памяти можно функцией GlobalAlloc.
HANDLE GlobalAlloc ( UINT uFlags // Атрибуты DWORD dwSize // Размер выделяемого блока в байтах );
Атрибуты указывают способ выделения памяти, например, если нужно заполнить ее нулями, то следует использовать флаг GMEM_ZEROINIT. Но достаточно просто выделить фиксированный блок памяти, с помощью флага GMEM_FIXED. Следует отметить, что константа GMEM_FIXED равна 0. Этим я воспользовался при написании примера к данной статье, где в качестве параметра передавал значение NULL. Вообще же, при фиксированном блоке памяти, вызов функции GlobalLock нужен скорее в эстетических целях, для получения указателя на блок. Далее нужно скопировать данные с помощью все той же memcpy. Логично предположить, что раз есть функция GetClipboardData, то есть и функция SetClipboardData, такое предположение, в данном случае, верно.
HANDLE SetClipboardData ( UINT uFormat // Формат запрашиваемых данных HANDLE handle // Идентификатор блока памяти );
Формат нужно указать текстовый - 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», который поставляется с архивом. На этом все. Скачать программу и исходный код к статье можно З Д Е С Ь
Статью написал 22.01.2008
|