№ | Макрос | Значение |
GHND | Блок может перемещаться и заполняется нулями | |
GMEM_DDESHARE | Память может использоваться для операций c буфером обмена | |
GMEM_DISCARDABLE | Память может быть выгружена | |
GMEM_LOWER | Память не перемещается | |
GMEM_NOCOMPACT | Блок может перемещаться в памяти | |
Блок не может изменять размер при операциях сборки мусора | ||
GMEM_NODISCARD | Блок не может быть выгружен | |
GMEM_SHARE | To же, что и GMEM_DDESHARE | |
GMEM_ZEROINIT | Выделенный блок памяти заполняется нулями | |
GPTR | Блок памяти не может перемещаться и заполняется нулями |
Память, выделенная при помощи функции GlobalAlloc(),становится глобальным системным объектом. Память, выделяемая для использования в буфере обмена, должна быть перемещаемой и разделяемой.
Как уже упоминалось, функция GlobalAlloc() возвращает дескриптор, а не указатель на выделенную память. Для получения указателя на область памяти, выделенную при помощи GlobalAlloc(), следует использовать функцию GlobalLock():
LPVOID GlobalLock(HGLOBAL hObj);
Функция GlobalLock() фиксирует в памяти объект (блок), дескриптор которого передается в параметре hObj. Зафиксированный объект не перемещается в памяти и не выгружается. Функция GlobalLock() возвращает адрес начала блока в случае успешного завершения или NULL при возникновении ошибки. Чтобы осуществить обращение к глобальным блокам памяти, эти блоки нужно обязательно зафиксировать. Таким образом, вызов функции GlobalLock() – это способ получения указателя на блок глобальной памяти. Фиксация блока также предохраняет память от обращения к ней других программ, пока с этой памятью работает Ваша программа.
После получения указателя на глобальный блок памяти необходимо скопировать в этот блок данные, которые Вы хотите поместить в буфер обмена. Когда копирование завершится, блок памяти можно разблокировать, вызвав функцию GlobalUnlock():
BOOL GlobalUnlock(HGLOBAL hObj);
Функция GlobalUnlock()возвращает нулевое значение в случае успешного завершения и ненулевое при возникновении ошибки. Дескриптор разблокируемого объекта передается в параметре hObj.
После копирования данных в глобальный блок памяти нужно открыть буфер обмена при помощи вызова функции OpenClipboard():
BOOL OpenClipboard(HWND hWnd);
Функция OpenClipboard()разрешает вызывающей программе доступ к буферу обмена (т.е. открывает его). После того как программа открыла буфер обмена, другие приложения использовать его не могут. Функция возвращает ненулевое значение, если буфер обмена успешно открыт, и нуль, если в данный момент буфер открыть невозможно. Параметр hWnd задает дескриптор окна, открывающего буфер обмена.
Когда буфер обмена успешно открыт, приложение должно очистить буфер обмена, вызвав функцию EmptyClipboard():
BOOL EmptyClipboard(void);
Функция EmptyClipboard() уничтожает всю ранее хранившуюся в буфере обмена информацию, освобождая все выделенные блоки памяти, и предоставляет буфер обмена текущему приложению. Перед вызовом этой функции буфер обмена должен быть открыт. Функция возвращает ненулевое значение в случае успешного завершения и нуль при возникновении ошибки.
Чтобы записать данные в буфер обмена, его следует настроить на память, содержащую эти данные. Это делается при помощи вызова функции SetClipboardData():
HANDLE SetClipboardData(UINT Format, HANDLE hData);
Функция SetClipboardData() настраивает буфер обмена на использование глобальной памяти, дескриптор которой указывается в параметре hData. Она возвращает новый дескриптор памяти, на которую настроен буфер обмена, либо NULL в случае возникновения ошибки.
Формат данных, записываемых в буфер обмена, задается параметром Format. Этот параметр может принимать предопределенные значения из таблицы 13.5, либо задавать собственный формат данных пользователя.
Таблица 13.5
Форматы и типы данных
№ | Формат | Тип данных |
CF_BITMAP | Растр (bitmap) в чистом виде | |
CF_DIB | Растр (bitmap) с заголовком BITMAPINFO | |
CF_DIF | Универсальный формат обмена (Data Interchange Format) | |
CF_DSPBITMAP | Пользовательское растровое изображение | |
CF_DSPENHMETAFILE | Пользовательский расширенный метафайл | |
CF_DSPMETAFILEPICT | Пользовательский метафайл | |
CF_DSPTEXT | Пользовательский текст | |
С F_ENHMETAFILE | Расширенный метафайл | |
CF_METAFILEPICT | Метафайл в стиле METAFILEPICT | |
CF_OEMTEXT | Текст в кодировке OEM | |
CF_OWNERDISPLAY | Пользовательский формат данных | |
CF_PALETTE | Цветовая палитра | |
CF_PENDATA | Формат для данных, связанных с электронным пером | |
CF_RIFF | Файл ресурсов (Resource Interchange File Format) | |
CF_SYLK | Символическая ссылка | |
CF_TEXT | Текст | |
CF_TIFF | Графика в формате TIFF | |
CF_WAVE | Звук в формате WAVE | |
CF_UNICODETEXT | Текст в кодировке UNICODE |
Для форматов CF_TEXT, CF_OEMTEXT и CF_UNICODETEXT текстовые блоки должны заканчиваться нулевым символом, а строки – комбинацией CR/LF – «возврат каретки»/«новая строка». Значения в диапазоне от CF_PRTVATEFIRST до CF_PRIVATELAST резервируются для локальных пользовательских форматов данных, а значения в диапазоне от CF_GDIOBJFIRST до CF_GDIOBJLAST – для пользовательских графических объектов.
После записи данных программа должна сразу же освободить буфер обмена при помощи функции CloseClipboard():
BOOL CloseClipboard (void);
Эта функция возвращает ненулевое значение в случае успешного завершения и нуль при возникновении ошибки.
Чтение данных аз буфера обмена. Для чтения данных из буфера обмена используется следующая процедура, состоящая из четырех шагов:
1) открыть буфер обмена;
2) получить указатель на данные, записанные в буфер обмена;
3) скопировать данные из буфера обмена;
4) закрыть буфер обмена.
Перечисленные шаги выполняются в следующем фрагменте программы:
if(OpenClipboard(hwnd))
{
hGin=GetClipboardData(CF_TEXT);
p=(char*)GlobalLock(hGin);
//
// Операторы копирования данных
// из глобальной памяти
//
GlobalUnlock(hGin);
CloseClipboard();
}
Чтобы получить доступ к данным, хранящимся в буфере обмена, последний должен быть открыт. После этого нужно получить дескриптор глобальной памяти, в которой хранятся данные хбуфера обмена. Это делается при помощи функции GetClipboardData():
HANDLE GetClipboardData(UINT Format);
Функция GetClipboardData() возвращает дескриптор глобальной памяти, содержащей информацию в заданном формате. Требуемый формат данных задается в параметре Format. Если в буфере обмена к моменту запроса нет данных, имеющих требуемый формат, функция возвращает значение NULL. В приведенном фрагменте программы запрашиваемый формат данных CF_TEXT.Для получения указателя по дескриптору, возвращаемому функцией GetClipboardData(), используется функция GlobalLock(),описанная выше.
Теперь программа должна скопировать данные из памяти буфера обмена в собственный локальный буфер. Поскольку функция GetClipboardData()возвращает дескриптор памяти, на которую настроен буфер обмена, программа должна скопировать данные до того, как управление будет возвращено Windows. Причину этого легко понять: после возврата управления Windows содержимое буфера обмена может быть изменено другим приложением.
Пример 13-3. Программа работы с буфером обмена Clipboard
Приведенная ниже программа демонстрирует доступ к буферу обмена: она записывает данные в этот буфер и читает их. Профамма предназначена для чтения только текстовых данных, хотя ее можно модифицировать таким образом, чтобы она могла читать данные и других форматов. Программа записывает текст в буфер обмена по команде меню Записать в буфер и читает данные по команде Прочесть из буфера. В буфер обмена можно также записать блок текста из другой программы (текстового редактора) и затем прочесть его при помощи данной программы.
// Демонстрация работы с буфером обмена Clipboard
#include <Windows.h>
#include <String.h>
#include "Clip.h"
#define Maxsize 100
LRESULT CALLBACK WindowFunc(HWND, UINT,
WPARAM, LPARAM);
char szWinName[]="МоеОкно"; // Имя класса окна
HGLOBAL hGout, hGin;
char text[]="Это текст для буфера обмена";
int WINAPI WinMain(HINSTANCE hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode)
{
HWND hwnd;
MSG msg;
HACCEL hAccel; // Для обработки акселераторов
WNDCLASS wcl; // Определить класс окна
wcl.hInstance=hThisInst; // Дескриптор приложения
wcl.lpszClassName=szWinName; // Имя класса окна
wcl.lpfnWndProc=WindowFunc; // Функция окна
wcl.style=0; // Стиль по умолчанию
wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка
wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор
wcl.lpszMenuName="Mymenu"; // Главное меню
wcl.cbClsExtra=0; // Без дополнительной информации
wcl.cbWndExtra=0;
wcl.hbrBackground=
(HBRUSH)GetStockObject(WHITE_BRUSH); //Белый фон
if(!RegisterClass(&wcl)) // Регистрируем класс окна
return 0;
hwnd=CreateWindow(szWinName, // Создать окно
"Работа с буфером обмена Clipboard ",
WS_OVERLAPPEDWINDOW, // Стиль окна
CW_USEDEFAULT, // x-координата
CW_USEDEFAULT, // y-координата
CW_USEDEFAULT, // Ширина
CW_USEDEFAULT, // Высота
HWND_DESKTOP, // Нет родител. окна
NULL, // Нет меню
hThisInst,// Дескриптор приложения
NULL); // Нет дополнит. аргументов
ShowWindow (hwnd, nWinMode); // Показать окно
UpdateWindow (hwnd); // и перерисовать
hAccel=LoadAccelerators(hThisInst,"Mymenu");
// Загрузить акселераторы
while(GetMessage(&msg,NULL,0,0))
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg); // Исполь. клавиатуру
DispatchMessage (&msg); // Возврат к Windows
}
return msg.wParam;
}
// Следующая функция вызывается операционной
// системой Windows и получает в качестве
// параметров сообщения из очереди сообщений
// данного приложения
LRESULT CALLBACK WindowFunc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
int i;
char *p;
char str[255];
switch(message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_OUTTOCLIP:
hGout=GlobalAlloc(GHND|GMEM_DDESHARE,
(DWORD)Maxsize);
p=(char*)GlobalLock(hGout);
strcpy(p,text); // Копирование текста
// в глобальную память
GlobalUnlock (hGout);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_TEXT,hGout);
CloseClipboard();
MessageBox(hwnd, text,
"Записано в буфер обмена",
MB_OK);
}
break;
case ID_READFROMCLIP:
if(OpenClipboard(hwnd))
{
hGin=GetClipboardData(CF_TEXT);
p=(char*)GlobalLock(hGin);
// Начинаем копировать текст
// из глобальной памяти */
for(i=0; i<Maxsize; i++)
str[i]= *p++;
str[i]= '\0'; // конец строки
// Закончили копировать текст
GlobalUnlock(hGin);
CloseClipboard();
MessageBox(hwnd, text,
"Прочитано из буфера обмена",
MB_OK);
}
}
break;
case WM_DESTROY: // Завершение программы
PostQuitMessage(0);
break;
default:
// Все сообщения, не обрабатываемые в
// данной функции, направляются на обработку
// по умолчанию
return DefWindowProc(hwnd,message,
wParam,lParam);
}
return 0;
}
Для этой программы необходим следующий файл ресурсов Clipboard.rc:
#include <Windows.h>
#include "Clip.h"
MYMENU MENU
{
POPUP "Данные"
{
MENUITEM "Записать в буфер", ID_OUTTOCLIP
MENUITEM "Прочесть из буфера",ID_READFROMCLIP
}
}
MYMENU ACCELERATORS
{
VK_F1, ID_OUTTOCLIP, VIRTKEY
VK_F2, ID_READFROMCLIP, VIRTKEY
}
Кроме того, потребуется файл определений Clip.h:
#define ID_OUTTOCLIP 101
#define ID_READFROMCLIP 102
![]() |
Работу этой программы иллюстрирует рис. 13.3.
Рис. 13.3. Пример работы с буфером обмена Clipboard
Литература
1. Емельянов А.А., Власова Е.А., Денисов Д.В., Емельянова Н.З. Основы программирования для информатиков и инженеров. Часть 1: Алгоритмизация и программирование на языке «С». – М.: ММИЭИФП, 2004. – 208 с.
2. Керниган Б., Ритчи Д. Язык программирования Си. – М.: Финансы и статистика, 2001. – 352 с.
3. Круглински Д. Дж., Уингоу С., Шеферд Дж. Программирование на Microsoft Visual С++ 6.0 для профессионалов. – СПб.: Питер; М.: Русская редакция, 2001. – 864 с.
4. Крупник А.Б. Изучаем Си. – СПб.: Питер, 2002. – 256 с.
5. Крупник А.Б. Изучаем С++. – СПб.: Питер, 2002. – 251 с.
6. Ламот А. Программирование игр для Windows: советы профессионала. – М.: Издательский дом «Вильямс», 2004. – 880 с.
7. Шилдт Г. Программирование на С и С++ для Windows. – К.: Торгово-издательское бюро BHV, 2001. – 408 с.
* Селекторные кнопки иногда называют «радиокнопками» (Прим. ред.)
* Если в папке уже есть файл с таким именем, то необходимо помнить, что его старое содержимое после сохранения будет потеряно, если не принять специальных мер по сохранению резервной копии