Буфер обмена с++

Обсуждение любых программ, не имеющих отношения к Total Commander.

Модераторы: d-view, Моторокер, Avada, CaptainFlint, Nik

Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

VadiMGP писал(а):Еще одно, хотя тут голову на отсечение не дам, но насколько я помню нет необходимости сначала проверять CF_UNICODETEXT, а потом CF_OEMTEXT. Эти форматы автоматически конвертируются один в другой и всегда присутствуют вместе. И CF_TEXT тоже.
Это чисто пример работы с несколькими форматами. Одним из них спокойно может оказаться CF_BITMAP, зависит от задачи.
VadiMGP писал(а):Уточнение. Для вызова IsClipboardFormatAvailable не нужно вызывать OpenClipboard. Даже рекомендуется наоборот, сначала убедиться, что есть нужный нам формат, и только в этом случае открывать буфер.
Действительно, так даже лучше. Вначале определяем, есть ли в буфере формат, который нас устроит, а потом открываем буфер:

Код: Выделить всё

	static const UINT desired_formats[]={CF_TEXT, CF_BITMAP}; // перечисляем форматы, которые нам надо обработать
	int fmt=GetPriorityClipboardFormat(&desired_formats, TSIZE(desired_formats)); // возвращает первый подходящий формат из массива, или -1, если не подошел ни один, или 0, если буфер пуст

	if (!fmt) MessageBox(0, "Clipboard is empty.", "Clipboard viewer", MB_ICONINFORMATION);
	else if (fmt<0) MessageBox(0, "Clipboard contains data in unknown format.", "Clipboard viewer", MB_ICONINFORMATION);
	else if (OpenClipboard(0)) {
		if (fmt==CF_TEXT) {
			HANDLE hclip=GetClipboardData(CF_TEXT);
			// обрабатываем текст
			if (hclip) MessageBox(0, (char*)hclip, "Clipboard text (ANSI)", MB_ICONINFORMATION); 
		} 
		else if (fmt==CF_BITMAP) {
			// обрабатываем картинку
			MessageBox(0, "Clipboard contains bitmap", "Clipboard viewer", MB_ICONINFORMATION); 
		} 
		CloseClipboard(); 
	}
А для простого получения текста вполне достаточно такого кода:

Код: Выделить всё

	if (IsClipboardFormatAvailable(CF_TEXT)&&OpenClipboard(0)) {
		HANDLE hclip=GetClipboardData(CF_TEXT);
		if (hclip) MessageBox(0, (char*)hclip, "Clipboard text (ANSI)", MB_ICONINFORMATION); 
		CloseClipboard(); 
	}
Само собой, делать это нужно при получении уведомления WM_DRAWCLIPBOARD. И вместо выдачи сообщения нужно скопировать текст во внутренний буфер, а после закрытия буфера обрабатывать данные.

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


Я так и не понял, в чем дело, но у меня на одном компе указанный выше пример получения текста из буфера при указани 0 в качестве окна работает, на другом - нет. Тупо возвращает нулевой дескриптор, и ошибку 1418. Я уже думаю, может, там она чуяла, что у процесса уже есть окно, и цеплялась к нему?.. Во, нашел причину - почему-то при трассировке кода в Visual Studio 2008, если я ставлю брейкпоинт между вызовами OpenClipboard и GetClipboardData, первая буфер открывает, но последняя возвращает 0! :?
VadiMGP
Сообщения: 1625
Зарегистрирован: Ср мар 21, 2007 20:58

Сообщение VadiMGP »

Код: Выделить всё

HANDLE hclip=GetClipboardData(CF_TEXT);
      if (hclip) MessageBox(0, (char*)hclip, "Clipboard text (ANSI)", MB_ICONINFORMATION);
Я бы не стал передавать в MessageBox переменную типа HANDLE. Иди знай, что у этих пчел на уме. Лучше так.

Код: Выделить всё

if (hclip) 
{
   LPSTR txt=(LPSTR)GlobalLock(hclip);
   MessageBox(0, txt,"Clipboard text (ANSI)", MB_ICONINFORMATION);
   GlobalUnlock(hclip);
}
Последний раз редактировалось VadiMGP Вс апр 25, 2010 22:03, всего редактировалось 1 раз.
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

Возможно, я так и делал бы, но в описании функции GetClipboardData нет ни слова о необходимости вызова GlobalLock для возвращаемого дескриптора. Единственный намек - указание, что дескриптор нельзя закрывать и оставлять заблокированным. Но так как между вызовами OpenClipboard и CloseClipboard его содержимое измениться не может, все должно работать и без блокировки.

Кстати, в твоем примере не хватает явного приведения возвращаемого функцией GlobalLock значения к типу LPSTR. И, кстати, сам по себе LPSTR - это уже указатель на символ, поэтому звездочка в объявлении переменной txt не нужна.
VadiMGP
Сообщения: 1625
Зарегистрирован: Ср мар 21, 2007 20:58

Сообщение VadiMGP »

MVV
В явном виде там, действительно, такое не написано, но есть пример использования.
Кстати, в твоем примере не хватает явного приведения возвращаемого функцией GlobalLock значения к типу LPSTR. И, кстати, сам по себе LPSTR - это уже указатель на символ, поэтому звездочка в объявлении переменной txt не нужна.
Это точно, второпях сглупил, сейчас поправлю.
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

Забавно, в примере тоже явное приведение типов отсутствует. Ощущение, что пример никогда не пытались компилировать. :D
VadiMGP
Сообщения: 1625
Зарегистрирован: Ср мар 21, 2007 20:58

Сообщение VadiMGP »

MVV писал(а):Забавно, в примере тоже явное приведение типов отсутствует
А, всё нормально. GlobalLock возвращает LPVOID, а он приводится к любому типу. :)
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

А вот не должен.

Любой указатель приводится к типу LPVOID, так как указатель на что-то определенное является указателем вообще (очевидно). Но отсюда вовсе не следует, что указатель вообще является указателем на что-то конкретное. В условиях жесткой типизации молча компилить такое недопустимо. 6-я студия не компилит. 7, 8 - не знаю, лень виртуальную машину запускать для проверки.

Типо, адрес больницы есть адрес вообще. Но адрес вообще вовсе не всегда есть адрес больницы. :D И если мы попытаемся, считая здание по указанному адресу больницей, войти в него там, где в больнице вход, можем запросто влипнуть в стену, если здание окажется, скажем, школой. :lol:
VadiMGP
Сообщения: 1625
Зарегистрирован: Ср мар 21, 2007 20:58

Сообщение VadiMGP »

MVV
Что самое смешное ты и прав и не прав.
Во-первых, в 2008 тоже не компиляется, выдает ошибку 2440 (cannot convert from 'type1' to 'type2'). По крайней мере, с жесткой проверкой типов. В этом ты прав.
А во-вторых, оказывается, что
MVV писал(а):... адрес больницы есть адрес вообще.
не всегда верно. В MSDN написано
C2440 can be caused if you attempt to convert a pointer to member to void*. The following sample generates C2440.

Код: Выделить всё

// C2440.cpp
class B {
public:
   void  f(){;}

   typedef void (B::*pf)();

   void f2(pf pf) {
       (this->*pf)();
       void* pp = (void*)pf;   // C2440
   }

   void f3() {
      f2(f);
   }
};
Но с больницей трудно провести аналогию, поэтому воспользуемся классикой - морская свинка еще не значит, что свинка. :)
Ответить