Работа с буфером обмена (clipboard)


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

1. Простейшие приемы работы с буфером обмена.

Прежде чем поместить в буфер обмена какую-либо информацию, ваша программа (далее просто окно) должна его открыть, используя функцию OpenClipboard. Однако следует учесть тот факт, что одновременно только одно окно может открыть буфер обмена. Следую хорошему тону программирования - если мы что-либо открыли, то нужно и закрыть. Работа с буфером обмена не является исключением для этого правила, следовательно, когда окно закончит работу, оно должно закрыть буфер обмена, вызвав функцию CloseClipboard.

После того как программа открыла буфер обмена, она должна его очистить от предыдущего содержания, для чего следует вызвать функцию EmptyClipboard. В обязанности этой функции входит посылка сообщения WM_DESTROYCLIPBOARD предыдущему владельцу буфера обмена, освобождение ресурсов, связанных с данными в буфере обмена. После этих операций данная функция передает в монопольное использование буфер обмена окну, которое вызвало функцию OpenClipboard.

После того как мы открыли буфер обмена и очистили его, мы имеем полное право помещать в него свои данные в различных форматах, используя функцию SetClipboardData (см. описание функции для описания стандартных форматов данных).

Чтобы извлечь информацию из буфера обмена, окно должно вызвать функцию GetClipboardData.
Данная функция в качестве параметра принимает формат буфера обмена, для того чтобы извлечь данные в этом формате. Если в буфер обмена данные поместила другая программа, вы можете проверить доступные форматы данных перед их непосредственным извлечением, используя функцию IsClipboardFormatAvailable.

Полученную теоретическую информацию следует применить на практике. Ниже приведены примеры работы с буфером обмена, в качестве форматов данных будет использован текст и изображение, поскольку работа с буфером обмена является типичной для любого формата данных, разница лишь в способе формирования исходных данных.

Пример записи и чтения текста.
CString source;
//в эту переменную нужно записать текст, который в дальнейшем поместится в буфер обмена
//запись текста в буфер обмена
if(OpenClipboard())//открываем буфер обмена
{
   HGLOBAL hgBuffer;
   char* chBuffer;
   EmptyClipboard(); //очищаем буфер
   hgBuffer= GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1);//выделяем память
   chBuffer= (char*)GlobalLock(hgBuffer); //блокируем память
   strcpy(chBuffer, LPCSTR(source));
   GlobalUnlock(hgBuffer);//разблокируем память
   SetClipboardData(CF_TEXT, hgBuffer);//помещаем текст в буфер обмена
   CloseClipboard(); //закрываем буфер обмена
}

//чтение текста из буфера обмена
CString fromClipboard;//в эту переменную сохраним текст из буфера обмена
if ( OpenClipboard() )//открываем буфер обмена
{
   HANDLE hData = GetClipboardData(CF_TEXT);//извлекаем текст из буфера обмена
   char* chBuffer= (char*)GlobalLock(hData);//блокируем память
   fromClipboard = chBuffer;
   GlobalUnlock(hData);//разблокируем память
   CloseClipboard();//закрываем буфер обмена
}


Пример записи и чтения изображения (bitmap).
//запись изображения в буфер обмена
if ( OpenClipboard() )//открываем буфер обмена
{
   EmptyClipboard(); //очищаем буфер
   //подготовим изображение для буфера обмена
   //в качестве изображения поместим снимок рабочего стола
   CDC memDC, dc;

   HWND hwnd = ::GetDesktopWindow();
   HDC hdc = ::GetWindowDC(hwnd);

   dc.Attach(hdc);
   memDC.CreateCompatibleDC(&dc);

   CBitmap bm;
   CRect rect;

   ::GetWindowRect(hwnd, &rect);
   CSize sz(rect.Width(), rect.Height());

   bm.CreateCompatibleBitmap(&dc, sz.cx, sz.cy);
   CBitmap* oldbm = memDC.SelectObject(&bm);
   memDC.BitBlt(0, 0, sz.cx, sz.cy, &dc, 0, 0, SRCCOPY);
 
   //помещаем данные в буфер обмена
   SetClipboardData(CF_BITMAP, bm.m_hObject);
   CloseClipboard(); //закрываем буфер обмена

   memDC.SelectObject(oldbm);
   ::ReleaseDC(hwnd, dc.Detach());

}

//чтение изображения из буфера обмена
if ( OpenClipboard() )//открываем буфер обмена
{
   //извлекаем данные из буфера обмена
   HBITMAP handle = (HBITMAP)GetClipboardData(CF_BITMAP);
   CBitmap * bm = CBitmap::FromHandle(handle);

   //отображаем данные из буфера
   BITMAP bit; 
   bm->GetBitmap(&bit);
   CClientDC cdc(this);
   CDC dc;
   dc.CreateCompatibleDC(&cdc);
   dc.SelectObject(bm);
   cdc.BitBlt(0, 0, bit.bmWidth, bit.bmHeight, &dc, 0, 0, SRCCOPY);

   CloseClipboard();//закрываем буфер обмена
}


Подводя итог этого раздела можно выделить следующие основные шаги для записи и чтения данных при работе с буфером обмена. Для того чтобы записать данные в буфер обмена, вы должны выполнить следующую последовательность действий:
  • Открыть буфер обмена функцией OpenClipboard
  • Очистить содержимое буфера обмена функцией EmptyClipboard
  • Заказать функцией GlobalAlloc глобальный блок памяти, имеющий размер, достаточный для размещения записываемых в буфер обмена данных
  • Заблокировать полученный блок памяти функцией GlobalLock
  • Записать в заблокированный блок памяти данные
  • Разблокировать блок памяти функцией GlobalUnlock
  • Поместить данные в буфер обмена функцией SetClipboardData
  • Закрыть буфер обмена функцией CloseClipboard

Процедура чтения данных из буфера обмена тоже проста. Приложение должно сделать следующее:
  • Открыть буфер обмена функцией OpenClipboard
  • Вызвать функцию GetClipboardData
  • Заблокировать блок памяти, идентификатор которого получен от функции GetClipboardData, функцией GlobalLock
  • Переписать данные из заблокированного буфера данных Clipboard в буфер, заказанный специально для этого приложением
  • Разблокировать блок памяти, идентификатор которого получен от функции GetClipboardData, функцией GlobalUnlock
  • Закрыть буфер обмена функцией CloseClipboard

 
« Предыдущая статья   Следующая статья »