Что такое код setclipboarddata

Содержание

Работа с буфером обмена (clipboard) / C++ для начинающих / C++

Содержание:

  • Введение.
  • 1. Простейшие приемы работы с буфером обмена.
  • 2. Нестандартные форматы данных буфера обмена.
  • 3. Функции для работы с буфером обмена.
  • 4. Демонстрационное приложение.
  • 5. Ссылки.

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

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);

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

2. Нестандартные форматы данных буфера обмена.

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

Для того чтобы зарегистрировать новый формат буфера обмена, используйте функцию RegisterClipboardFormat . Рассмотрим простой пример использования этой функции:

//объявим некую структуру
struct MyClipboardData
<
CString strName;
int nAge;
>;
//помещаем данные в буфер обмена
UINT format = RegisterClipboardFormat(«MY_CUSTOM_FORMAT»); //регистрируем наш формат данных
if(OpenClipboard())//для работы с буфером обмена его нужно открыть
<
//заполним нашу структуру данными
MyClipboardData data;
data.strName = «Vasya_Pupkin»;
data.nAge = 25;

HGLOBAL hgBuffer;
EmptyClipboard(); //очищаем буфер
hgBuffer= GlobalAlloc(GMEM_DDESHARE, sizeof(MyClipboardData));//выделим память
MyClipboardData* buffer = (MyClipboardData*)GlobalLock(hgBuffer);
//запишем данные в память
*buffer = data;
//поместим данные в буфер обмена
GlobalUnlock(hgBuffer);
SetClipboardData(format, hgBuffer); //помещаем данные в буфер обмена
CloseClipboard();//после работы с буфером, его нужно закрыть
>

//прочитаем наши данные из буфера обмена
//вызываем второй раз, чтобы просто получить формат
UINT format = RegisterClipboardFormat(«MY_CUSTOM_FORMAT»);
MyClipboardData data;
if ( OpenClipboard() )
<
//извлекаем данные из буфера
HANDLE hData = GetClipboardData(format);
MyClipboardData* buffer = (MyClipboardData*)GlobalLock( hData );

//заполняем нашу структуру полученными данными
data = *buffer;

GlobalUnlock( hData );
CloseClipboard();
>

Два различных приложения или две копии одного приложения могут зарегистрировать формат с одним и тем же именем, при этом функция RegisterClipboardFormat вернет один и тот же идентификатор формата. Поэтому два приложения всегда смогут «договориться», если они знают имя нестандартного формата данных.

3. Функции для работы с буфером обмена.

Данная функция удаляет определяемое окно просмотра буфера обмена из цепочки окон просмотра буфера обмена. Что это значит? А значит это следующее: чтобы получать сообщения от буфера обмена, наша программа должна заявить операционной системе об этом, вызвав функцию SetClipboardViewer , и если вдруг настанет такой момент, когда мы больше не хотим получать сообщения от буфера обмена (например: закрытие приложения), мы должны вызвать данную функцию.

В качестве параметров данная функция принимает дескрипторы окон: hWndRemove — идентифицирует окно, которое будет удалено из цепочки; hWndNewNext — дескриптор окна, которое следует за hWndRemove окном в цепочке окон просмотра буфера обмена, т.е. дескриптор, возвращенный ранее функцией SetClipboardViewer .

После вызова данной функции, всем окнам в цепочке окон просмотра буфера обмена будет послано сообщение WM_CHANGECBCHAIN. Обработав данное сообщение окно обычно возвращает FALSE, следовательно, данная функция обычно будет возвращать FALSE. Однако если имеется только одно окно в цепочке, возвращаемое значение — обычно TRUE.

Следует также отметить, что окно, идентифицированное как hWndNewNext, заменяет hWndRemove окно в цепочке.

Данная функция закрывает буфер обмена.

Данная функция не имеет входных параметров. В случае успешного завершения возвращаемое значение будет отлично от нуля, в противном случае — ноль. Для более подробной информации об ошибке следует вызвать функцию GetLastError .

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

Данная функция возвращает число различных форматов данных в текущем буфере обмена.

Данная функция не имеет входных параметров. В случае успешного завершения функции, возвращаемое значение — это число различных форматов данных в текущем буфере обмена, в противном случае — ноль. Для более подробной информации об ошибке следует вызвать функцию GetLastError .

Данная функция очищает буфер обмена и освобождает дескрипторы данных в нем. Затем функция назначает монопольное использование буфера обмена окну, которое вызвало функцию OpenClipboard .

Данная функция не имеет входных параметров. В случае успешного завершения возвращаемое значение будет отлично от нуля, в противном случае — ноль. Для более подробной информации об ошибке следует вызвать функцию GetLastError .

Следует отметить, что перед вызовом данной функции, прикладная программа должна открыть буфер обмена, используя функцию OpenClipboard . Если приложение при открытии буфера обмена определяет дескриптор окна NULL, EmptyClipboard завершается успешно, но устанавливает владельца буфера обмена как NULL.

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

В качестве входного параметра данная функция принимает идентификатор формата данных буфера обмена. format — определяет формат буфера обмена, о котором известно, что он является доступным. Для того чтобы начать перечисление форматов буфера обмена, нужно установить format в 0, тогда функция возвращает первый доступный формат буфера обмена. При последующих вызовах, во время перечисления, в format устанавливается результат предыдущего обращения к EnumClipboardFormat .

В случае успешного завершения, возвращаемое значение — формат буфера обмена, который следует за заданным форматом, иными словами, следующий доступный формат буфера обмена. В случае завершения с ошибкой, возвращаемое значение 0. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError . Следует отметить, что если буфер обмена не открыт, функция завершается с ошибкой.

При перечислении форматов данных следует помнить, что если больше нет форматов буфера обмена, при вызове данной функции, возвращаемое значение будет равно 0. Однако, функция GetLastError возвращает значение NO_ERROR. Это позволяет делать различие между завершением с ошибкой и концом операции перечисления.

Следует отметить, что перед перечислением форматов буфера обмена, необходимо открыть его. Чтобы открыть буфер обмена, используйте функцию OpenClipboard . Данная функция перечисляет форматы по порядку, как они были помещены в буфер обмена.

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

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

if (OpenClipboard())
<
UINT uFormat = EnumClipboardFormats(0); //получаем первый доступный

while (uFormat)
<
//тут можно что-либо делать
.

uFormat = EnumClipboardFormats(uFormat); //берем следующий формат
>
CloseClipboard();
>

Данная функция извлекает данные из буфера обмена в заданном формате. Предварительно необходимо открыть буфер обмена.

В качестве параметра uFormat функция принимает идентификатор формата, данные в котором необходимо извлечь из буфера обмена.

В случае успешного завершения данной функции, возвращаемое значение — дескриптор объекта буфера обмена в заданном формате, в противном случае — возвращаемое значение NULL. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

Следует отметить, что при вызове данной функции операционная система выполнит скрытое преобразование форматов данных. Таблица преобразования форматов:

Формат Буфера обмена Формат преобразования Платформа поддержки

CF_BITMAP CF_DIB Windows NT/2000, Windows 95/98
CF_BITMAP CF_DIBV5 Windows 2000
CF_DIB CF_BITMAP Windows NT/2000, Windows 95/98
CF_DIB CF_PALETTE Windows NT/2000, Windows 95/98
CF_DIB CF_DIBV5 Windows 2000
CF_DIBV5 CF_BITMAP Windows 2000
CF_DIBV5 CF_DIB Windows 2000
CF_DIBV5 CF_PALETTE Windows 2000
CF_ENHMETAFILE CF_METAFILEPICT Windows NT/2000, Windows 95/98
CF_METAFILEPICT CF_ENHMETAFILE Windows NT/2000, Windows 95/98
CF_OEMTEXT CF_TEXT Windows NT/2000, Windows 95/98
CF_OEMTEXT CF_UNICODETEXT Windows NT/2000
CF_TEXT CF_OEMTEXT Windows NT/2000, Windows 95/98
CF_TEXT CF_UNICODETEXT Windows NT/2000
CF_UNICODETEXT CF_OEMTEXT Windows NT/2000
CF_UNICODETEXT CF_TEXT Windows NT/2000

Данная функция извлекает из буфера обмена имя заданного зарегистрированного формата. Функция копирует имя в заданный буфер.

В качестве входных параметров данная функция получает идентификатор формата данных буфера обмена ( format ), адрес буфера для названия формата ( lpszFormatName ) и длину буфера ( cchMaxCount ). Идентификатор формата lpszFormatName определяет тип формата, название которого будет извлечено. Этот параметр не должен определять какой-либо из предопределенных форматов буфера обмена. lpszFormatName — указывает на буфер, который должен принять имя формата; cchMaxCount — определяет максимальную длину строки (в символах), которая будет скопирована в буфер. Следует учесть, что если имя превышает это ограничение, оно усекается.

В случае успешного завершения, возвращаемое значение — длина строки (в символах), скопированной в буфер, в противном случае, возвращаемое значение равно 0, указывая, что запрошенный формат не существует или предопределен. Чтобы получать дополнительные данные об ошибке, вызовите функцию GetLastError .

Данная функция извлекает дескриптор окна текущего владельца буфера обмена.

Данная функция не имеет входных параметров. В случае успешного завершения, возвращаемое значение — дескриптор окна, которое является в данный момент владельцем буфера обмена. В противном случае, возвращаемое значение NULL. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

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

Данная функция извлекает дескриптор первого окна в цепочке окон просмотра буфера обмена.

Данная функция не имеет входных параметров. В случае успешного завершения, возвращаемое значение — дескриптор первого окна в цепочке окон просмотра буфера обмена. Если же не определено ни одно окно просмотра буфера обмена, возвращаемое значение NULL. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

Данная функция извлекает дескриптор окна, которое в настоящее время имеет открытый буфер обмена.

Данная функция не имеет входных параметров. В случае успешного завершения, возвращаемое значение — дескриптор окна, которое имеет открытый буфер обмена. Если нет окна, которое открыло буфера обмена, возвращаемое значение NULL, т.е. если открыть буфер обмена и не передать в функцию OpenClipboard дескриптор окна, бефер будет открыт, но не связан с каким-либо окном. В таком случае данная функция вернет NULL. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

Данная функция возвращает значение первого доступного формата буфера обмена в заданном списке.

В качестве входных параметров данная функция принимает массив целых чисел без знака, идентифицирующих форматы буфера обмена ( paFormatPriorityList ) и число введенных данных в массиве paFormatPriorityList ( cFormats ). Следует учесть, что cFormats не должно быть больше, чем число вводимых данных в списке.

В случае успешного завершения, возвращаемое значение — первый формат буфера обмена в списке, для которого данные являются доступными. Данная функция вернет NULL, если буфер обмена пуст, или -1 (-1) — если буфер обмена содержит данные, но не в каком-либо из заданных форматов. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

Данная функция определяет, содержит ли буфер обмена данные в заданном формате.

В качестве входного параметра данной функции является идентификатор формата данных ( format ).

Если формат буфера обмена доступен, возвращаемое значение не 0, в противном случае функция вернет 0. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

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

Данная функция открывает буфер обмена для работы с ним и препятствует другим прикладным программам изменять содержимое буфера обмена.

В качестве входных параметров данная функция принимает дескриптор окна ( hWndNewOwner ). Этот дескриптор идентифицирует окно, которое будет связано с открытым буфером обмена. Однако можно не задавать этот дескриптор, в таком случае, открытый буфер обмена будет связан с текущей задачей.

В случае успешного завершения данной функции, возвращается значение отличное от 0, в противном случае, возвращаемое значение 0. Чтобы получить дополнительные данные об ошибках, обратитесь к функции GetLastError .

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

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

В качестве входного параметра этой функции ( lpszFormat ) служит адрес строки, которая именует новый формат.

В случае успешного завершения, возвращаемое значение идентифицирует зарегистрированный формат буфера обмена, в противном случае функция возвращает 0. Чтобы получать дополнительные данные об ошибке, вызовите функцию GetLastError .

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

Данная функция помещает данные в буфер обмена в заданном формате.

В качестве входных параметров данная функция принимает формат буфера обмена ( uFormat ) и дескриптор данных ( hMem ). В качестве формата буфера обмена функция может принимать любой из зарегистрированных или стандартных форматов буфера обмена; hMem — идентифицирует данные в заданном формате.

В случае успешного завершения, возвращаемое значение — дескриптор данных, в противном случае — NULL. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

Ниже приведен список стандартных форматов данных буфера обмена с описанием, которые может принимать uFormat :

  • CF_BITMAP — Дескриптор к точечному рисунку (HBITMAP).
  • CF_DIB — Объект в памяти содержит структуру BITMAPINFO, сопровождаемую растровыми битами.
  • CF_DIF — Формат обмена данными программы Arts’.
  • CF_DSPBITMAP — Растровый формат отображения данных на дисплее, связанный с собственным форматом. Параметр hMem должен быть дескриптором данных, которые могут отображаться в растровом формате вместо частным образом форматируемых данных.
  • CF_DSPENHMETAFILE — Формат отображения улучшенного метафайла связанного с собственным форматом. Параметр hMem должен быть дескриптор данных, которые могут отображаться в улучшеннном формате метафайла вместо частным образом форматируемых данных.
  • CF_DSPMETAFILEPICT — Формат отображения данных метафайла-картинки, связанного с собственным форматом. Параметр hMem должен быть дескриптором данных, которые могут отображаться в формате метафайла-картинки вместо частным образом форматируемых данных.
  • CF_DSPTEXT — Формат отображения текста, связанный с собственным форматом. Параметр hMem должен быть дескриптором данных, которые могут отображаться в текстовом формате вместо частным образом форматируемых данных.
  • CF_ENHMETAFILE — Дескриптор улучшенного метафайла (HENHMETAFILE).
  • От CF_GDIOBJFIRST до CF_GDIOBJLAST — Диапазон целочисленных значений для определяемых программой форматов буфера обмена объекта GDI. Дескрипторы, связанные с форматами буфера обмена в этом диапазоне автоматически не удаляются, при использовании функции GlobalFree , когда очищается буфер обмена. Также, при использовании значений в этом диапазоне, параметр hMem — не дескриптор к объекту GDI, а дескриптор, помещенный функцией GlobalAlloc с флажками GMEM_MOVEABLE и GMEM_DDESHARE.
  • CF_HDROP — Дескриптор типа HDROP — это тот, который идентифицирует список файлов. Прикладная программа может извлечь информацию о файлах, передавая дескриптор функции DragQueryFile .
  • CF_LOCALE — Данные являются дескриптором локального идентификатора, связанного с текстом в буфере обмена. Когда вы закрываете буфер обмена, если он содержит данные CF_TEXT, а не данные CF_LOCALE, система автоматически устанавливает формат CF_LOCALE в текущем месте ввода информации. Вы можете использовать формат CF_LOCALE, чтобы сопоставлять различные места действия с текстом буфера обмена. Прикладная программа, которая вставляет текст из буфера обмена, может извлечь этот формат, чтобы определить, какой набор символов использовался, чтобы создать текст. Обратите внимание, что буфер обмена не поддерживает обычный текст в многокомпонентных наборах символов. Чтобы добиться этого, взамен используйте форматированный текстовый тип данных, такой как RTF. Windows NT: система использует кодовую страницу, связанную с CF_LOCALE, чтобы неявно преобразовать из CF_TEXT в CF_UNICODETEXT. Следовательно, правильная таблица кодовой страницы используется для преобразования.
  • CF_METAFILEPICT — Дескриптор метафайла изображает формат как определено структурой METAFILEPICT. При передаче дескриптора CF_METAFILEPICT посредством динамического обмена данными (прямой ввод данных (DDE)), прикладная программа, ответственная за удаление hMem должна также освободить метафайл, упоминаемый дескриптором CF_METAFILEPICT.
  • CF_OEMTEXT — Текстовый формат, содержащий символы в OEM наборе символов. Каждые строка заканчивается комбинацией возврат каретки / перевод строки (carriage return/linefeed)(CR-LF). Символ пробела сообщает о конце данных.
  • CF_OWNERDISPLAY — Собственный формат отображения данных. Владелец буфера обмена должен отображать, и модифицировать окна просмотра буфера обмена, и принимать сообщения WM_ASKCBFORMATNAME, WM_HSCROLLCLIPBOARD, WM_PAINTCLIPBOARD, WM_SIZECLIPBOARD и WM_VSCROLLCLIPBOARD. Параметр hMem должен иметь значение NULL.
  • CF_PALETTE — Дескриптор цветовой палитры. Всякий раз, когда прикладная программа помещает данные в буфер обмена, которые зависят от цветовой палитры или назначает цветовую палитру, она должна поместить в буфер обмена также и палитру. Если буфер обмена содержит данные в формате CF_PALETTE (логическая цветовая палитра), прикладная программа должна использовать функции SelectPalette и RealizePalette , чтобы реализовать (сравнить) любые другие данные в буфере обмена в зависимости от этой логической палитры. При отображении данных буфера обмена, буфер обмена Windows всегда использует как свою текущую палитру любого объекта в буфере обмена, который находится в формате CF_PALETTE.
  • CF_PENDATA — Дополнительные данные для пера в Microsoft Windows для Pen Computing (Компьютерного пера).
  • От CF_PRIVATEFIRST до CF_PRIVATELAST — Диапазон целых значений для собственных форматов буфера обмена. Дескрипторы, связанные с собственными форматами буфера обмена автоматически не освобождаются; владелец буфера обмена должен освобождать такие дескрипторы, обычно в ответ на сообщение WM_DESTROYCLIPBOARD.
  • CF_RIFF — Представляет звуковые данные более сложные, чем они могут быть представлены в стандартном звуковом формате CF_WAVE.
  • CF_SYLK — Формат Символической Связи Microsoft (SYLK) (Microsoft Symbolic Link).
  • CF_TEXT — Текстовый формат. Каждая строка оканчивается комбинацией возврата каретки / перевода строки (CR-LF). Символ пробела сообщает о конце данных. Используйте этот формат для текста ANSI.
  • CF_WAVE — Представляет звуковые данные в одном из стандартных звуковых форматах, таких как импульсно-кодовой модуляции 11 кГц или 22 кГц (ИКМ) (PCM- pulse code modulation).
  • CF_TIFF — Формат Файла Тегированного Изображения (TIFF — Tagged-image file format).
  • CF_UNICODETEXT — Только Windows NT: Формат текста Юникода. Каждая строка оканчивается комбинацией возврата каретки / перевода строки (CR-LF). Символ пробела сообщает о конце данных.

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

Данная функция добавляет определяемое окно к цепочке окон просмотра буфера обмена.

В качестве входного параметра данной функции служит дескриптор окна ( hWndNewViewer ), идентифицирующий окно, которое будет добавлено к цепочке окон буфера обмена.

В случае успешного завершения, возвращаемое значение идентифицирует следующее окно в цепочке окон просмотра буфера обмена, однако если происходит ошибка или не имеется никаких других окон в цепочке окон просмотра буфера обмена, возвращаемое значение NULL. Чтобы получить дополнительные данные об ошибке, вызовите функцию GetLastError .

Следует отметить, что если окно является частью цепочки окон просмотра буфера обмена, оно должно обрабатывать сообщения WM_CHANGECBCHAIN и WM_DRAWCLIPBOARD, а также, удаляться из цепочки окон просмотра, вызовом функции ChangeClipboardChain — например, в ответ на сообщение WM_DESTROY.

4. Демонстрационное приложение.

В прикрепленном архиве содержится проект, который демонстрируют работу с буфером обмена.

ChangeClipboardChain, CloseClipboard, CountClipboardFormats, EmptyClipboard, EnumClipboardFormats, GetClipboardData, GetClipboardFormatName, GetClipboardOwner, GetClipboardViewer, GetOpenClipboardWindow, GetPriorityClipboardFormat, IsClipboardFormatAvailable, OpenClipboard, RegisterClipboardFormat, SetClipboardData, SetClipboardViewer.

GetClipboardData(CF_TEXT)

How to use GetClipboardData(CF_TEXT); without calling and use process id of this in C++?
and which libary does GetClipboardData(CF_TEXT) belong to?

1 Answer 1

GetClipboardData() is a Win32 API function.

The handle returned by GetClipboardData() must be first locked with GlobalLock() , then you can retrieve the char* pointer of the ANSI text in the clipboard (note that if you want to retrieve Unicode text, you should use the CF_UNICODETEXT format).

A sample code to retrieve the text from the clipboard and store it in a convenient std::string class instance follows (error management omitted for simplicity):

You can use C++ RAII pattern and manage error conditions using exceptions, something like this:

c++ setclipboarddata GetClipboardData(CF_TEXT)

winapi clipboard (1)

Как использовать GetClipboardData(CF_TEXT); без вызова и использования идентификатора процесса этого в C ++?
и к какой библиотеке принадлежит GetClipboardData(CF_TEXT) ?

GetClipboardData() возвращаемый GetClipboardData() должен быть сначала заблокирован с помощью GlobalLock() , тогда вы можете получить указатель char* текста ANSI в буфере обмена (обратите внимание, что если вы хотите получить текст Unicode, вы должны использовать формат CF_UNICODETEXT ).

Образец кода для извлечения текста из буфера обмена и сохранения его в удобном экземпляре std::string class (управление ошибками опущено для простоты):

Вы можете использовать шаблон C ++ RAII и управлять условиями ошибки с использованием исключений, примерно так:

Как работает буфер обмена в Windows

Недавно у меня появилась возможность выполнить отладку буфера обмена в Windows, и я решил, что хорошо бы поделиться информацией, которую удалось узнать. Буфер обмена — это тот компонент Windows, который многие из нас используют десятки (сотни?) раз в день, особо не размышляя об этом. Прежде чем взяться за это дело, я даже никогда не задумывался, как всё устроено. Как выяснилось, там столько интересного, что вы даже не можете себе представить. Сначала опишу, как приложения хранят разные типы данных в буфере обмена и как извлекают их оттуда, а затем — как приложения могут «прицепиться» к буферу и отслеживать изменения в нём. В обоих случае вы увидите отладочные записи, которые показывают, как получить доступ к данным из отладчика.

Начнём с обсуждения форматов буфера обмена. Такие форматы используются для описания, какие типы данные можно поместить в буфер. Там есть некоторое количество предопределённых стандартных форматов, которые может использовать приложение, вроде битового массива, текста ANSI, текста в Юникоде и TIFF. Windows также позволяет приложению установить собственный формат. Например, текстовый процессор может зарегистрировать формат, включающий в себя текст, форматирование и картинки. Конечно, это ведёт к определённой проблеме: что произойдёт, если вы скопируете данные из текстового редактора и вставите их в «Блокнот», который не понимает всего этого форматирования и не отображает картинки?

Выход — разрешить одновременное хранение данных в буфере обмена в нескольких форматах. Когда я раньше думал о буфере обмена, то представлял, что там хранится единственный объект («мой текст» или «моя картинка»), но на самом деле мои данные хранятся в буфере в разных формах. Программа, которая берёт информацию из буфера, получает её в том формате, который она может использовать.

Как же данные появляются в буфере обмена? Очень просто, приложение сначала объявляет о праве собственности на буфер обмена через функцию OpenClipboard. После этого программа может очистить буфер обмена командой EmptyClipboard и, наконец, поместить туда свои данные командой SetClipboardData. SetClipboardData принимает два параметра. Первый — это идентификатор одного из форматов буфера обмена, которые мы упоминали выше. Второй — дескриптор сегмента в памяти, который содержит данные в этом формате. Приложение может неоднократно вызывать команду SetClipboardData для каждого из форматов, какие она хочет поместить в буфер, от лучшего к худшему (поскольку то приложение, куда будут вставляться данные, выберет первый подходящий формат из списка). Чтобы облегчить жизнь разработчику, Windows автоматически обеспечивает конвертацию некоторых типов форматов для буфера обмена. По окончании процесса программа вызывает CloseClipboard.

Когда пользователь нажимает кнопку «Вставить», целевое приложение вызывает OpenClipboard и одну из следующих функций для определени я доступных форматов данных: IsClipboardFormatAvailable, GetPriorityClipboardFormat или EnumClipboardFormats. Если оно находит подходящий формат, то тогда вызывает GetClipboardData с идентификатором нужного формата в качестве параметра, чтобы получить данные. В конце приложение использует команду CloseClipboard для закрытия буфера.

Теперь взглянем, как с помощью отладчика определить, какие данные записаны в буфер обмена. (Заметьте, что все мои записи сделаны в системе Win7/2008 R2 — так что на других версиях ОС они могут выглядеть несколько иначе). Поскольку буфер является частью Win32k.sys, вам понадобится отладчик ядра. Я люблю использовать в качестве контрольной точки win32k!InternalSetClipboardData+0xe4 . В таком смещении хорошо то, что оно находится за регистром RDI, заполненным данными из SetClipboardData в структуре, известной как tagCLIP.

Вот как выглядит вызов к SetClipboardData от «Блокнота»:

Итак, теперь мы можем просмотреть содержимое RDI как tagCLIP и увидеть, что записано в буфер:

Fmt — это формат для буфера обмена. 0Xd — это число 13, что соответствует тексту в формате Юникода. Однако мы не можем просто запустить du по значению hData , потому что это дескриптор, а не прямой указатель на данные. Так что нужно поискать его в глобальной структуре win32k — gSharedInfo:

aheList в gSharedInfo содержит массив с дескрипторами, и последние два байта hData, умноженные на размер записи дескриптора, показывают адрес записи нашего дескриптора:

Если посмотреть phead со смещением 14, то мы получим наши данные (это смещение может отличаться на разных платформах):

Представим другой сценарий. Я скопировал какой-то текст из Wordpad, и команда SetClipboardData отработала определённое количество раз, чтобы разместить данные в разных форматах. Запись в формате Юникода выглядит так::

hData равен нулю! Почему так? Оказывается, буфер обмена позволяет приложению передавать нуль в качестве параметра SetClipboardData для определённого формата. Это означает, что приложение способно предоставить данные в данном формате, но сделает это позже, в случае необходимости. Если я захочу вставить текст в «Блокнот», для чего в буфере должен быть текст в Юникоде, Windows отправит сообщение WM_RENDERFORMAT в окно WordPad, и тогда WordPad предоставит данные в новом формате. Конечно, если приложение закрывается до того, как предоставило данные во всех форматах, Windows понадобятся все форматы. В этом случае Windows отправит сообщение WM_RENDERALLFORMATS, чтобы другие приложения могли использовать данные из буфера обмена после закрытия материнского приложения.

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

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

Функциональность Clipboard Viewer появилась ещё в версии Windows 2000, если не раньше. Принцип работы довольно простой: приложение, которое заинтересовано в получении уведомлений об изменении в буфере, вызывает SetClipboardViewer и передаёт дескриптор своего окна. Windows хранит этот дескриптор в структуре win32k, и каждый раз при изменении буфера обмена Windows отправляет сообщение WM_DRAWCLIPBOARD в зарегистрированное окно.

Конечно, зарегистрироваться для просмотра буфера могут несколько окон — как Windows справится с этим? Ну, если приложение вызывает SetClipboardViewer, а другое окно раньше уже зарегистрировалось для просмотра буфера обмена, то Windows возвращает новому окну значение дескриптора предыдущего окна. И теперь новое окно, следящее за буфером, обязано вызвать SendMessage каждый раз, когда получает WM_DRAWCLIPBOARD, и уведомить об изменении буфера следующее окно в цепочке тех, кто следит за буфером. Каждое из окон, следящих за буфером, также должно обрабатывать сообщения WM_CHANGECBCHAIN. Такие сообщения уведомляют все остальные окна об удалении одного звена в цепочке и сообщают, какое звено становится следующим в очереди. Это позволяет сохранить цепочку.

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

Чтобы справиться с такими проблемами, в Windows Vista добавили механизм прослушивания формата буфера обмена — Clipboard Format Listener. Он работает во многом так же, как просмотр буфера обмена, за исключением того, что Windows сама ведёт список приложений, которые прослушивают буфер, а не полагается на добропорядочность приложений, которые должны сохранять цепочку.

Если приложение хочет прослушивать буфер, оно вызывает функцию AddClipboardFormatListener и передаёт дескриптор своего окна. После этого обработчик сообщений окна будет получать сообщения WM_CLIPBOARDUPDATE. Когда приложение собирается завершить работу или больше не хочет получать уведомления, оно вызывает RemoveClipboardFormatListener.

Мы рассмотрели, как зарегистрировать просмотр/прослушивание буфера обмена. Теперь посмотрим, как с помощью отладчика определить, какие программы участвуют в этих процессах. Сначала нужно идентифицировать процесс в сессии, где мы хотим проверить мониторинг буфера обмена. Это может быть любой процесс win32 в этой сессии — он нужен нам просто для того, чтобы найти указатель на Window Station. В этом случае я бы использовал окно «Блокнота», как и раньше:

Далее посмотрим адрес Win32Process как win32k!tagPROCESSINFO и узнаем значение rpwinsta:

Это наша Window Station. Сливаем содержимое через dt:

Обратите внимание на поля spwndClipViewer, spwndClipboardListener и spwndClipOwnerfields. Здесь spwndClipViewer — это последнее зарегистрированное окно в цепочке тех, кто просматривает буфер обмена. Также spwndClipboardListener — последнее зарегистрированное окно прослушивания буфера в списке Clipboard Format Listener. Окно spwndClipOwner — это то окно, которое разместило данные в буфере обмена.

Ели мы знаем окно, то осталось несколько шагов, чтобы узнать, к какому процессу оно относится. Нас интересуют forspwndClipViewer, spwndClipboardListener и spwndClipOwner. Сначала запускаем dt, чтобы узнать значение tagWND. Для этой демонстрации мы используем spwndClipViewer:

Нас интересует только значение head — так что если смещение 0, делаем dt для того же адреса на _THRDESKHEAD:

Теперь запускаем dt для адреса, указанного в поле pti как tagTHREADINFO:

Теперь нам интересно только значение поля pEThread, которое мы можем передать в !thread:

Как видим, просмотр буфера обмена зарегистрировн от имени процесса viewer02.exe. Поскольку просмотр идёт по цепочке, определить следующий процесс в цепочке будет непросто. Но мы можем сделать это для тех, кто прослушивает буфер. Снова взглянем на нашу Window Station:

Если запустить dt на spwndClipboardListener, то увидим поле spwndClipboardListenerNext с указанием следующего прослушивающего процесса:

При достижении последнего процесса в списке прослушивающих буфер tagWND, значение его поля spwndClipboardListenerNext будет нулевым:

Используя адрес окна, мы можем тем же методом добраться до названия процесса. Как упоминалось ранее, поскольку tagWND — это структура ядра, ОС сама хранит указатели spwndClipboardListener/spwndClipboardListenerNext, так что они не могут привести к таким проблемам с отслеживанием буфера, как цепочки просмотра.

На этом заканчивается наш обзор буфера обмена Windows. Надеюсь, для вас он стал информативным. Хотите узнать больше о мониторинге буфера обмена? Вот хорошая статья MSDN об этом.

Thread: SetClipBoardData()

Thread Tools
Search Thread
Display
  • Linear Mode
  • Switch to Hybrid Mode
  • Switch to Threaded Mode

SetClipBoardData()

well, i’ve had a look as MSDN, and it’s really not a help.

if anyone could post a quick example of the code that will *work* i’ll love you forever.

Assuming you are interested in text. run this and then paste into any program (MSWord, notepad. etc).

Oh. and there is no need to «love me forever».

Что такое код setclipboarddata

I am using jeffrey richters’s example 22 LastMsgBoxInfoLib, modified to hook User32.dll’s SetClipboardData and GetClipboardData functions. But after hooking, neither the client app nor dll is able to successfully call OpenClipboard().
The dll is in win32 ;and client is in mfc. Visual Studiio 2005 SP1, Windows XP Sp3.
Here is the link to the project example I used:http://www.wintellect.com/Downloads/Windows%20via%20C++%20Code%20(December%201,%202007).zip
//This is a GetClipboardData replacement function inside dll
HANDLE WINAPI Hook_GetClipboardData(UINT uType)
< .

//Check if notepad or wordpad
if(_tcsicmp(allowedAppName, szProcessPathname) == 0)//If user allowed app send info to change value of clipboard
<

HANDLE nResult = ((PFNGETCLIPBOARDDATA)(PROC) g_GetClipboardData)(uType); //original hooked fn called.
//now call the openclipboard to set custom data in clipboard.
//This call fails
if(OpenClipboard(NULL))< //this call fails

. I never reach here.
>
return nResult;

//Code inside mfc client
Before hooking this call works, so I can set data in clipboard first time. But after hooking OpenClipboard() fails.

if(OpenClipboard()) <
HGLOBAL hClipboardData;
bool res = EmptyClipboard();
TCHAR* arr;
size_t bytes = (m_szCer.GetLength()+1)*sizeof(TCHAR);
hClipboardData = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,(m_szCer.GetLength()+1)*sizeof(TCHAR));
if (!hClipboardData) return;
arr=(TCHAR*)GlobalLock(hClipboardData);
_tcscpy(arr, LPCTSTR(m_szCer));
//This call always returns false;
res = GlobalUnlock(hClipboardData);//Here result is always false.
//Why the above call always fails.

VERIFY(SetClipboardData(CF_UNICODETEXT, hClipboardData));
res = CloseClipboard();

Also the following line in the function always returns false whether called before or after hooking.

res = GlobalUnlock(hClipboardData);//Here result is always false.

My idea was to try to unhook the the two clipboard function before I reset the clipboard second time, but no luck.
///this call is to set the hook, dwThread > LastClipBoardInfo_HookAllApps(TRUE,dwThreadId,»fsd»,»as». );
///and this call to unhook is
LastClipBoardInfo_HookAllApps(FALSE,dwThreadId,»»,»». );

Повреждение кучи во время SetClipboardData()

Я не уверен, что является основной причиной получения такой ошибки (Heap Corruption) из приведенного ниже кода. Когда я просматриваю программу, значение TCHAR правильно распределяется и копируется в данные буфера обмена. Тем не менее, он падает, когда он переходит к SetClipboardData (. ).

Может ли какой-нибудь гуру выявить ошибку?

Блок кучи в 04A781C0, измененный на 04A78282 прошлый запрошенный размер ba Windows вызвала точку останова в V4.exe.

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

Это также может быть связано с пользователем нажатие F12, в то время как V4.exe имеет фокус.

В окне вывода может быть больше диагностическая информация. Программа ‘[10840] V4.exe: «Родной» вышел с кодом 0 (0x0).

Использование Буфера обмена (Clipboard)


Перевод: Sergey Kulish
Источник: Using the Clipboard

Опубликовано: 07.07.2004
Исправлено: 05.03.2006
Версия текста: 1.0

В этой статье приводятся примеры решения следующих задач:

  • Реализация команд Вырезать (Cut), Копировать (Copy) и Вставить (Paste)
  • Создание окна просмотра буфера обмена (Clipboard Viewer)
  • Добавление окна в цепочку наблюдателей за буфером обмена

Реализация команд Вырезать (Cut), Копировать (Copy) и Вставить (Paste)

В этом разделе описано как реализовывать в приложении стандартные команды Вырезать , Копировать , и Вставить . Пример данного раздела использует эти методы для размещения данных в буфере обмена в следующих форматах: зарегистрированном, графическом (CF_OWNERDISPLAY), текстовом (CF_TEXT). Регистрируемый формат используется для представления прямоугольного или эллиптического окна текста, называемого меткой (label).

Выделение данных

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

Создание меню Правка (Edit)

Приложение должно загружать таблицу акселераторов (accelerator table) содержащую стандартные быстрые клавиши (keyboard accelerators) для пунктов меню Правка . Для обработки этих клавиш необходимо добавить функцию TranslateAccelerator в цикл обработки сообщений вашего приложения. Для получения дополнительной информации об быстрых клавишах смотрите статью Быстрые клавиши (Keyboard Accelerators).

Обработка сообщения WM_INITMENUPOPUP

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

Далее приведен пример обработки WM_INITMENUPOPUP для приложения, которое мы назовем Label.

Функция InitMenu определена так:

Обработка сообщения WM_COMMAND

Для работы с командами меню, добавьте обработку WM_COMMAND в оконную процедуру главного окна вашего приложения. Далее приведен пример обработки WM_COMMAND в оконной процедуре приложения Label.

Для выполнения команд Копировать (Copy) и Вырезать (Cut) , оконная процедура вызывает определенную в приложении функцию EditCopy. Подробно эта функция рассматривается в разделе “Копирование информации в буфер обмена”. Для выполнения команды Вставить (Paste) , оконная процедура вызывает определенную в приложении функцию EditPaste. Подробно эта функция рассматривается в разделе “Вставка информации из буфера обмена.”

Копирование информации в буфер обмена

Определенная в приложении Label функция EditCopy копирует текущее выделение в буфер обмена. При этом функция выполняет следующие действия:

  1. Открывает буфер обмена, вызывая функцию OpenClipboard.
  2. Очищает буфер обмена вызывая функцию EmptyClipboard.
  3. Вызывает по одному разу функцию SetClipboardData для каждого формата буфера обмена поддерживаемого приложением.
  4. Закрывает буфер обмена вызовом функции CloseClipboard.

В зависимости от текущего выделения, функция EditCopy копирует либо диапазон текста, либо структуру, представляющую метку (label, отсюда и название нашего приложения — Label) целиком. Структура LABELBOX, определена так.

Ниже приведена функция EditCopy:

Вставка данных из буфера обмена

Реализованая в приложении Label функция EditPaste вставляет содержимое буфера обмена. При этом функция выполняет следующие действия:

1. Открывает буфер обмена вызовом функции OpenClipboard .
2. Определяет доступный формат для извлечения данных из буфера обмена.
3. Получает дескриптор данных в выбранном формате вызовом функции GetClipboardData .
4. Вставляет копию данных в документ.

ПРЕДУПРЕЖДЕНИЕ

Дескриптор, возвращаемый GetClipboardData, на протяжении работы с ним продолжает принадлежать буферу обмена, поэтому приложение не должно его освобождать или оставлять заблокированным

5. Закрывает буфер обмена вызывая функцию CloseClipboard .

Если метка выделена и указано место вставки, функция EditPaste вставляет текст из буфера обмена в это место. Если нет выделения или не указано место вставки, функция создает новую метку, используя определенную в приложении структуру LABELBOX. Структура LABELBOX помещается в буфер обмена используя регистрируемый формат буфера обмена.

Определение структуры LABELBOX было приведено выше.

Далее приведена функция EditPaste.

Регистрация формата буфера обмена

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

Обработка сообщений WM_RENDERFORMAT и WM_RENDERALLFORMATS

Если окно передает нулевой дескриптор в функцию SetClipboardData , необходимо обрабатывать сообщения WM_RENDERFORMAT и WM_RENDERALLFORMATS для отображения запрашиваемых данных.

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

Чтобы отрисовывать формат буфера обмена оконная процедура должна поместить дескриптор данных для буфера обмена, используя функцию SetClipboardData . При этом буфер обмена нельзя открывать до вызова функции SetClipboardData .

Приложение Label обрабатывает сообщения WM_RENDERFORMAT и WM_RENDERALLFORMATS следующим образом:

В обоих случаях, оконная процедура вызывает пользовательскую функцию RenderFormat , которая определена следующим образом:

Обработка сообщения WM_DESTROYCLIPBOARD

Окно может обработать сообщение WM_DESTROYCLIPBOARD для того, чтобы освободить ресурсы задействованные на поддержку задерживаемой отрисовки формата. К примеру приложение Label, при копировании в буфер обмена, распределяет память под локальный объект. Приложение уничтожает этот объект в ответ на сообщение WM_DESTROYCLIPBOARD , как показано далее.

Использование самоотображающегося (Owner-Display) формата буфера обмена

Если окно помещает информацию в буфер обмена используя формат буфера обмена CF_OWNERDISPLAY , то оно должно делать следующее:

  • Обрабатывать сообщение WM_PAINTCLIPBOARD. Это сообщение посылается владельцу буфера обмена когда часть окна просмотра буфера обмена должна быть перерисована.
  • Обрабатывать сообщение WM_SIZECLIPBOARD. Это сообщение посылается владельцу буфера обмена когда окно просмотра буфера обмена изменяет размер или меняется его содержимое.

ПРИМЕЧАНИЕ

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

  • Обрабатывать сообщения WM_HSCROLLCLIPBOARD и WM_VSCROLLCLIPBOARD. Эти сообщения посылаются владельцу буфера обмена при прокрутке в окне просмотра буфера обмена.
  • Обрабатывать сообщение WM_ASKCBFORMATNAME. Окно просмотра буфера обмена посылает это сообщение приложению для получения имени самоотображающегося формата.

Оконная процедура для приложения Label обрабатывает эти сообщения следующим образом:

Создание окна просмотра буфера обмена

Окно просмотра буфера обмена отображает текущее содержимое буфера обмена, и получает сообщение когда содержимое буфера обмена изменяется. Для создания окна просмотра буфера обмена, ваше приложение должно делать следующее:

  • Добавить своё окно в цепочку наблюдателей за буфером обмена.
  • Обрабатывать сообщение WM_CHANGECBCHAIN.
  • Обрабатывать сообщение WM_DRAWCLIPBOARD.
  • Удалить окно из цепочки наблюдателей за буфером обмена до уничтожения этого окна.

Добавление окна в цепочку наблюдателей за буфером обмена

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

Следующий пример демонстрирует добавление окна в цепочку наблюдателей за буфером обмена в ответ на сообщение WM_CREATE.

Приведенные далее примеры кода:

  • Обрабатывают сообщение WM_CHANGECBCHAIN
  • Удаляют окно из цепочки наблюдателей за буфером обмена
  • Обрабатывают сообщение WM_DRAWCLIPBOARD
  • Показывают пример просмотрщика буфера обмена

Обработка сообщения WM_CHANGECBCHAIN

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

Следующий пример показывает, как обрабатывать сообщение WM_CHANGECBCHAIN .

Удаление окна из цепочки наблюдателей за буфером обмена

Для удаления себя из цепочки наблюдателей за буфером обмена, окно вызывает функцию ChangeClipboardChain. Далее приводится пример удаления окна из цепочки наблюдателей за буфером обмена в ответ на сообщение WM_DESTROY.

Обработка сообщения WM_DRAWCLIPBOARD

Сообщение WM_DRAWCLIPBOARD уведомляет окно просмотра буфера обмена о том, что содержимое буфера обмена изменилось. Окну следует сделать следующее при поступлении сообщения WM_DRAWCLIPBOARD :

  1. Определить, какой из доступных форматов буфера обмена следует использовать для отображения.
  2. Извлечь данные буфера обмена и отобразить их в окне. Или, если формат буфера обмена CF_OWNERDISPLAY, послать сообщение WM_PAINTCLIPBOARD владельцу буфера обмена.
  3. Послать сообщение следующему окну в цепочке просмотра буфера обмена.

Пример обработки сообщения WM_DRAWCLIPBOARD приведен в следующем листинге:

SetClipboardData info Overview Group

The SetClipboardData function places data on the clipboard in a specified clipboard format. The window must be the current clipboard owner, and the application must have called the OpenClipboard function. (When responding to the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages, the clipboard owner must not call OpenClipboard before calling SetClipboardData .)

HANDLE SetClipboardData(

Parameters

uFormat Specifies a clipboard format. This parameter can be a registered format or any of the standard clipboard formats listed in the following Remarks section. For information about registered clipboard formats, see the RegisterClipboardFormat function.
hMem Identifies the data in the specified format. This parameter can be NULL, indicating that the window provides data in the specified clipboard format (renders the format) upon request. If a window delays rendering, it must process the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages.

Once SetClipboardData is called, the system owns the object identified by the hMem parameter. The application can read the data, but must not free the handle or leave it locked. If the hMem parameter identifies a memory object, the object must have been allocated using the GlobalAlloc function with the GMEM_MOVEABLE and GMEM_DDESHARE flags.

Return Values

If the function succeeds, the return value is the handle of the data.

If the function fails, the return value is NULL. To get extended error information, call GetLastError .

Remarks

The uFormat parameter can identify a registered clipboard format, or it can be one of the following values:

A handle to a bitmap ( HBITMAP ).

A memory object containing a BITMAPINFO structure followed by the bitmap bits.

Software Arts� Data Interchange Format.

Bitmap display format associated with a private format. The hMem parameter must be a handle of data that can be displayed in bitmap format in lieu of the privately formatted data.

Enhanced metafile display format associated with a private format. The hMem parameter must be a handle of data that can be displayed in enhanced metafile format in lieu of the privately formatted data.

Metafile-picture display format associated with a private format. The hMem parameter must be a handle of data that can be displayed in metafile-picture format in lieu of the privately formatted data.

Text display format associated with a private format. The hMem parameter must be a handle of data that can be displayed in text format in lieu of the privately formatted data.

A handle of an enhanced metafile ( HENHMETAFILE ).

CF_GDIOBJFIRST through CF_GDIOBJLAST

Range of integer values for application-defined GDI object clipboard formats. Handles associated with clipboard formats in this range are not automatically deleted using the GlobalFree function when the clipboard is emptied. Also, when using values in this range, the hMem parameter is not a handle to a GDI object, but is a handle allocated by the GlobalAlloc function with the GMEM_DDESHARE and GMEM_MOVEABLE flags.

A handle of type HDROP that identifies a list of files. An application can retrieve information about the files by passing the handle to the DragQueryFile functions.

The data is a handle to the locale identifier associated with text in the clipboard. When you close the clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets the CF_LOCALE format to the current input locale. You can use the CF_LOCALE format to associate a different locale with the clipboard text.

An application that pastes text from the clipboard can retrieve this format to determine which character set was used to generate the text.

Note that the clipboard does not support plain text in multiple character sets. To achieve this, use a fomatted text data type such as RTF instead.

Windows NT: The system uses the code page associated with CF_LOCALE to implicitly convert from CF_TEXT to CF_UNICODETEXT. Therefore, the correct code page table is used for the conversion.

Handle of a metafile picture format as defined by the METAFILEPICT structure. When passing a CF_METAFILEPICT handle by means of dynamic data exchange (DDE), the application responsible for deleting hMem should also free the metafile referred to by the CF_METAFILEPICT handle.

Text format containing characters in the OEM character set. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.

Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive the WM_ASKCBFORMATNAME, WM_HSCROLLCLIPBOARD, WM_PAINTCLIPBOARD, WM_SIZECLIPBOARD, and WM_VSCROLLCLIPBOARD messages. The hMem parameter must be NULL.

Handle of a color palette. Whenever an application places data in the clipboard that depends on or assumes a color palette, it should place the palette on the clipboard as well.

Data for the pen extensions to the Microsoft Windows for Pen Computing.

CF_PRIVATEFIRST through CF_PRIVATELAST

Range of integer values for private clipboard formats. Handles associated with private clipboard formats are not freed automatically; the clipboard owner must free such handles, typically in response to the WM_DESTROYCLIPBOARD message.

Represents audio data more complex than can be represented in a CF_WAVE standard wave format.

Microsoft Symbolic Link (SYLK) format.

Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data. Use this format for ANSI text.

Represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz pulse code modulation (PCM).

, который освобождает дескриптор в SetClipboardData (CF_BITMAP, HBITMAP)?

Мое понимание заключается в том, что, когда вы добавляете дескриптор в буфер обмена, буфер обмена тогда владеет дескриптором, и вы несете ответственность за его удаление, и его не следует удалять. Это то, что он говорит здесь: https://msdn.microsoft.com/en-us/library/windows/desktop/ms649051%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

Если SetClipboardData успешно, система принадлежит объект, идентифицированный : параметр hMem. Приложение не может записывать или освобождать данные после того, как право собственности было передано системе, но оно может заблокировать и считать данные, пока не будет вызвана функция CloseClipboard. (Память должна быть разблокирована до закрытия буфера обмена.) Если параметр hMem идентифицирует объект памяти, объект должен быть , назначенный с помощью функции с флагом GMEM_MOVEABLE.

И действительно я вижу много примеров, когда люди называют GlobalAlloc(), поставить какой-нибудь текст в глобальной ручке, вызовите SetClipboardData(), а затем не освобождает глобальную ручку, так как буфер обмен она владеет.

Но в случае данных HBitmap, добавленных через SetClipboardData(CF_BITMAP, hBitmap) , я вижу много примеров, как эти:

В этих случаях код делает удалить HBITMAP после добавления его в буфер обмена.

Есть ли разница между дескриптором HBITMAP и дескриптором GlobalAlloc() относительно буфера обмена? Есть ли что-то особенное в CF_BITMAP, которое является исключением из правила, и буфер обмена копий ручка вместо принадлежит? Можете ли вы указать мне официальную (MSDN) документацию, объясняющую разницу?

Edit:

Обратите внимание, что в случае точечного рисунка автор прямо говорит:

// копия была сделана в буфере обмена, поэтому мы можем удалить

Создан 19 авг. 15 2015-08-19 04:32:32 M Katz

Илон Маск рекомендует:  Написание plugin'ов для internet explorer
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL

If the clipboard contains data in the CF_PALETTE (logical color palette) format, the application should use the SelectPalette and RealizePalette functions to realize (compare) any other data in the clipboard against that logical palette.

When displaying clipboard data, Windows clipboard always uses as its current palette any object on the clipboard that is in the CF_PALETTE format.