介绍
windows剪切板的内容包含很多不同的格式,例如:CF_TEXT、CF_BITMAP、CF_METAFILEPICT、CF_SYLK、CF_DIF、CF_TIFF、CF_OEMTEXT、CF_DIB、CF_PALETTE、CF_PENDATA、CF_RIFF、CF_WAVE、CF_UNICODETEXT、CF_ENHMETAFILE、CF_HDROP、CF_LOCALE、CF_DIBV5等。这里只涉及文本( CF_TEXT 和 CF_UNICODETEXT )和文件( CF_HDROP )格式的获取和设置,其它格式暂未涉及 。
代码
根据不同的字符集环境,我们定义了共用的字符串类型tstring,并且定义了可变长度的vvtstring用来存储文件列表。
#ifdef _UNICODE
typedef std::wstring tstring;
#else
typedef std::string tstring;
#endif //_UNICODE
typedef std::vector
vtstring;
typedef std::vector
vvtstring;
定义
Clipboard类实现了这些功能,它的主要函数功能介绍如下:readFromClipBoard获取剪切板的文本内容,writeToClipBoard设置剪切板的文本内容;copyFileToClipboard把文件列表设置到剪切板中,readFileFromClipBoard获取剪切板中文件列表。
class Clipboard {
public:
static bool readFromClipBoard(tstring& str);
static bool writeToClipBoard(const tstring& str);
static bool copyFileToClipboard(const vvtstring& fileList);
static bool readFileFromClipBoard(vvtstring& fileList);
private:
};
实现
readFromClipBoard根据字符集的类型,判断剪切板内容是否是文本内容。使用GetClipboardData获取文件内容并保存在传出参数str中。
bool Clipboard::readFromClipBoard(tstring& str) {
#ifdef _UNICODE
const UINT CF_TCTEXT = CF_UNICODETEXT;
#else
const UINT CF_TCTEXT = CF_TEXT;
#endif
if (!IsClipboardFormatAvailable(CF_TCTEXT) || !OpenClipboard(NULL)) {
return false;
}
HANDLE hglb = GetClipboardData(CF_TCTEXT);
if (hglb != NULL) {
const TCHAR *lpstr = (const TCHAR *)GlobalLock(hglb);
if (lpstr != 0) {
str.assign(lpstr);
GlobalUnlock(hglb);
}
}
CloseClipboard();
return true;
}
writeToClipBoard先打开剪切板并清空剪切板中的内容,然后根据需要设置的文本内容的长度分配相应的内存空间,接着把写入分配的内存,SetClipboardData完成设置。
bool Clipboard::writeToClipBoard(const tstring& str) {
if (OpenClipboard(NULL)) {
EmptyClipboard();
size_t clipSize = str.length() * sizeof(TCHAR);
HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, clipSize);
if (hglb) {
TCHAR *buff = (TCHAR *)GlobalLock(hglb);
memcpy(buff, str.c_str(), clipSize);
GlobalUnlock(hglb);
#ifdef _UNICODE
const UINT CF_TCTEXT = CF_UNICODETEXT;
#else
const UINT CF_TCTEXT = CF_TEXT;
#endif
SetClipboardData(CF_TCTEXT, hglb);
}
CloseClipboard();
}
return false;
}
copyFileToClipboard复制文件列表到剪切板。DROPEFFECT_COPY表明剪切板中的文件列表是复制,DROPEFFECT_MOVE表明是剪切。文件列表在剪切板中的格式是每个文件名以0结尾,最后一个文件名以两个0结尾。
bool Clipboard::copyFileToClipboard(const vvtstring& fileList)
{
if (fileList.empty()) {
return false;
}
UINT uDropEffect = RegisterClipboardFormat(L"Preferred DropEffect");
HGLOBAL hGblEffect = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(DWORD));
LPDWORD lpdDropEffect = (LPDWORD)GlobalLock(hGblEffect);
*lpdDropEffect = DROPEFFECT_COPY;
GlobalUnlock(hGblEffect);
DROPFILES stDrop = {0};
stDrop.pFiles = sizeof(DROPFILES);
stDrop.pt.x = 0;
stDrop.pt.y = 0;
stDrop.fNC = FALSE;
stDrop.fWide = TRUE;
int filenameLength = 0;
for (auto iter = fileList.begin(); iter != fileList.end(); ++ iter) {
const vtstring& file = (*iter);
filenameLength += file.size();
}
int totalLength = sizeof(DROPFILES) + filenameLength * sizeof(TCHAR) +
(fileList.size() - 1) * sizeof(TCHAR) + 2 * sizeof(TCHAR);
HGLOBAL hGblFiles = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, totalLength);
char* lpData = (char*)GlobalLock(hGblFiles);
memcpy(lpData, &stDrop, sizeof(DROPFILES));
char *lpStart = lpData + sizeof(DROPFILES);
int iStart = 0;
auto iter = fileList.begin();
do {
const vtstring& file = (*iter);
memcpy(lpStart + iStart, &file.front(), file.size() * sizeof(TCHAR));
++ iter;
if (iter == fileList.end()) {
break;
}else {
iStart += file.size() * sizeof(TCHAR);
iStart += 1 * sizeof(TCHAR); // '\0'
}
}while(true);
GlobalUnlock(hGblFiles);
if (OpenClipboard(NULL)) {
EmptyClipboard();
SetClipboardData(CF_HDROP,hGblFiles);
SetClipboardData(uDropEffect,hGblEffect);
CloseClipboard();
return true;
}else {
return false;
}
}
readFileFromClipBoard获取剪切板中的文件列表。首先根据剪切板中的格式来判断当前剪切板中的内容是否是文件类型(CF_HDROP)。然后使用DragQueryFile获取剪切板中的文件。
bool Clipboard::readFileFromClipBoard(vvtstring& fileList) {
if(!IsClipboardFormatAvailable(CF_HDROP) || !OpenClipboard(NULL)) {
return false;
}
HDROP hDrop=(HDROP)GetClipboardData(CF_HDROP);
int iFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
for (int i = 0; i < iFiles; i++) {
int length = DragQueryFile(hDrop, i, NULL, 0);
TCHAR* lpszFile = (TCHAR*)GlobalAlloc(GPTR, (length + 1) * sizeof(TCHAR));
DragQueryFile(hDrop, i, lpszFile, length + 1);
vtstring file(lpszFile, lpszFile + length);
fileList.push_back(file);
GlobalFree(lpszFile);
}
CloseClipboard();
return true;
}