C++ (VC): 如何检测Windows 剪贴板是否包含CF_TEXT 数据?

C++ (VC): How to detect whether Windows clipboard contains CF_TEXT data?

我完全是 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;
} 

对于如何解决最后一个问题的任何建议,我将不胜感激。

在使用 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的return类型是void指针。因此,根据您已经使用 IsClipboardFormatAvailable 确定的数据格式,您必须将其转换为相应的类型。 Windows 数据类型已记录 here

谢谢你的回答,这比我在看到你的 post 之前想出的那个有用得多。这是我笨拙且不安全的解决方案(它替换了我问题中的相应代码)。我将改用您更好的解决方案!

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 文件),我让我的代码生成一个空文件而不是退出。再次感谢!