текст — C ++ (VC): как определить, содержит ли буфер обмена Windows данные CF_TEXT?

Я новичок в C ++, но мне удалось изменить код других людей и, наконец, собрать программу, которая записывает буфер обмена Windows в текстовый файл, с текстом, закодированным в кодовую страницу, указанную в качестве параметра командной строки для Программа (например, MyProg.exe 437) запишет текст в кодовую страницу 437. Если кодовая страница не указана, программа запишет текстовый файл в стандартную кодовую страницу Windows 1252.

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

Я искал ответ безуспешно. Вот мой код VC2010 (который я не совсем понимаю, но, кажется, работает, когда буфер обмена содержит CF_TEXT; это не работает с CF_UNICODETEXTКстати, на выходе получается просто несколько байтов.):

#include <stdafx.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <codecvt> // for wstring_convert
#include <locale>  // for codecvt_byname

using namespace std;

void BailOut(char *msg)
{
fprintf(stderr, "Exiting: %s\n", msg);
exit(1);
}

int main(int argc, char* argv[])
{
std::string codepage = ".1252";
if (argc > 1) {
std::string cpnum = argv[1];
codepage = "."+cpnum;
}

HANDLE clip;
string clip_text = "";
// exit if clipboard not available
if (!OpenClipboard(NULL))
BailOut("Can't open clipboard");

clip = GetClipboardData(CF_TEXT);
clip_text = (char*)clip;
CloseClipboard();

// create conversion routines
typedef std::codecvt_byname<wchar_t,char,std::mbstate_t> codecvt;
std::wstring_convert<codecvt> cp1252(new codecvt(".1252"));
std::wstring_convert<codecvt> outpage(new codecvt(codepage));

std::string OutFile = "#clip.txt"; // output file name
ofstream OutStream;  // open an output stream
OutStream.open(OutFile, ios::out | ios::trunc);

// make sure file is successfully opened
if(!OutStream)
{
cout << "Error opening file " << OutFile << " for writing.\n";
return 1;
}
// convert to DOS/Win codepage number in "outpage"OutStream << outpage.to_bytes(cp1252.from_bytes(clip_text)).c_str();
OutStream << endl;
OutStream.close(); // close output stream
return 0;
}

Буду благодарен за любые предложения о том, как решить эту последнюю проблему.

3

Решение

Прежде чем вы получите данные из буфера обмена с помощью GetClipboardData Функция, вы должны проверить, что буфер обмена содержит данные в том формате, который вы ожидаете. Это можно сделать с помощью IsClipboardFormatAvailable функционировать следующим образом:

if(IsClipboardFormatAvailable(CF_TEXT))
{
// The clipboard contains null-terminated ANSI string.
}
else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
{
// The clipboard contains null-terminated Unicode string.
}

Затем вы должны открыть буфер обмена и получить дескриптор буфера буфера обмена следующим образом (при условии, что буфер обмена содержит строку ANSI):

if(!OpenClipboard(NULL)) return;
HGLOBAL hglb = GetClipboardData(CF_TEXT);

Затем вы должны получить эксклюзивный доступ к данным, используя GlobalLock функция Только в случае успеха вы можете безопасно получить доступ к данным

if (hglb != NULL)
{
LPTSTR lptstr = GlobalLock(hglb);
if (lptstr != NULL)
{
// Read the contents of lptstr which just a pointer to the string.

// Don't forget to release the lock after you are done.
GlobalUnlock(hglb);
}
}
CloseClipboard();

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

5

Другие решения

Спасибо за этот ответ, который гораздо полезнее, чем тот, который я придумал до того, как увидел ваш пост. Вот мое неловкое и небезопасное решение (которое заменяет соответствующий код в моем вопросе). Я собираюсь использовать ваше гораздо лучшее решение вместо этого!

HANDLE clip;
std::string clip_text = "";
// exit if clipboard not available
if (!OpenClipboard(NULL))
BailOut("Can't open clipboard");

UINT textOK = 0;
UINT currentFormat = 0;
while(currentFormat = EnumClipboardFormats(currentFormat))
{
if(currentFormat == 1)
textOK = 1;
}
// only get text if text exists in clipboard
if (textOK == 1)
{
clip = GetClipboardData(CF_TEXT);
clip_text = (char*)clip;
}
CloseClipboard();

По разным причинам (программа, которая запускает это, ожидает найти файл # CLIP.TXT), я заставил мой код создавать пустой файл, а не выходить из него. Еще раз спасибо!

0