1.以下代码实现了操作剪贴板的功能,当程序的字符集合为ASCII时,该程序可以正常运行,但当是UNICODE时,SetClipBoard函数就会出现异常,经过反复测试发现是由于内存分配不足引起的.对于UNICODE字符集,每个字符是16位的,也就是2个字节,而使用GlobalAlloc进行空间申请时,则是按字节申请的,所以导致实际申请的空间不足,因此增加了一个宏判断,如代码中所示.
void CTestMFCView::OnEditCopydata()
{
// TODO: Add your command handler code here
TCHAR szText[] = _T("Hello clip board!");
size_t iLen = 0;
if(::OpenClipboard(m_hWnd))
{
::EmptyClipboard();
iLen = _tcsclen(szText) + 1;
#ifdef _UNICODE
iLen *= 2;
#endif
HANDLE hData = ::GlobalAlloc(GHND,iLen);
LPTSTR pData = (LPTSTR)::GlobalLock(hData);
::_tcscpy(pData,szText);
::GlobalUnlock(hData);
::SetClipboardData(CF_TEXT,hData);
::CloseClipboard();
}
}
void CTestMFCView::OnEditPastedata()
{
// TODO: Add your command handler code here
TCHAR szText[MAX_PATH];
if(::OpenClipboard(m_hWnd))
{
HANDLE hData = ::GetClipboardData(CF_TEXT);
if(hData != NULL)
{
LPTSTR pData = (LPTSTR)::GlobalLock(hData);
if(_tcsclen(pData) < MAX_PATH)
{
_tcscpy(szText,pData);
}
::GlobalUnlock(hData);
}
}
::CloseClipboard();
CClientDC dc(this);
CRect rect;
this->GetClientRect(&rect);
dc.DrawText(szText,&rect,DT_CENTER);
}
2.以下代码实现拷贝粘贴位图的功能
void CTestMFCView::OnEditCopybitmap()
{
// TODO: Add your command handler code here
HBITMAP hBitmap = ::CreateBitmap(200,300,1,32,NULL);
HDC hdc = ::GetDC(NULL);
HDC hdcMem = ::CreateCompatibleDC(hdc);
SelectObject(hdcMem,hBitmap);
HBRUSH hBrush = ::CreateSolidBrush(RGB(255,0,0));
RECT rect = {0,0,200,300};
::FillRect(hdcMem,&rect,hBrush);
::TextOut(hdcMem,0,0,_T("text"),_tcsclen(_T("text")));
DeleteObject(hBrush);
// 将创建的位图画在客户端
CClientDC clientDC(this);
CDC* cdc = new CDC();
cdc->Attach(hdcMem);
clientDC.BitBlt(0,0,200,300,cdc,0,0,SRCCOPY);
cdc->Detach();
DeleteDC(hdcMem);
::ReleaseDC(NULL,hdc);
// 将位图拷贝到剪贴板中
if(::OpenClipboard(m_hWnd))
{
::EmptyClipboard();
::SetClipboardData(CF_BITMAP,hBitmap);
::CloseClipboard();
}
::DeleteObject(hBitmap);
}
void CTestMFCView::OnEditPastebitmap()
{
// TODO: Add your command handler code here
if(::OpenClipboard(m_hWnd))
{
HBITMAP hBitmap = (HBITMAP)::GetClipboardData(CF_BITMAP);
if(hBitmap != NULL)
{
if(m_hBitmap != NULL)
{
DeleteObject(m_hBitmap);
m_hBitmap = NULL;
}
BITMAP bmp;
::GetObject(hBitmap,sizeof(BITMAP),&bmp);
//将位图保存在成员变量中,以便在OnDraw函数中可以使用
m_hBitmap = ::CreateBitmapIndirect(&bmp);
HDC hdc = ::GetDC(NULL);
HDC hdcBitmap = CreateCompatibleDC(hdc);
HDC hdcMember = CreateCompatibleDC(hdc);
::SelectObject(hdcBitmap,hBitmap);
::SelectObject(hdcMember,m_hBitmap);
::BitBlt(hdcMember,0,0,200,300,hdcBitmap,0,0,SRCCOPY);
::DeleteDC(hdcBitmap);
::DeleteDC(hdcMember);
::ReleaseDC(NULL,hdc);
}
::CloseClipboard();
}
}
3.以下代码是实现对HDROP类型数据的剪切,实际是对文件名称得复制和粘贴
void CTestMFCView::OnEditCopyhdrop()
{
// TODO: Add your command handler code here
// 由于HDROP引用的内存块最后是以两个NULL字符作为结束标志的,所以在文件名中不能存在两个连续的NULL字符,否则得到的结果将会错误(失去两个连续NULL之后的信息)
TCHAR szFiles[4][9] = {
_T("C://a.txt"),
_T("C://b.txt"),
_T("C://c.txt"),
_T("")
};
if(::OpenClipboard(m_hWnd))
{
::EmptyClipboard();
int nSize = sizeof(DROPFILES) + sizeof(szFiles);
HANDLE hData = ::GlobalAlloc(GHND,nSize);
LPDROPFILES pDropFile = (LPDROPFILES)::GlobalLock(hData);
pDropFile->pFiles = sizeof(DROPFILES);
#ifdef _UNICODE
pDropFile->fWide = TRUE;
#else
pDropFile->fWide = FALSE;
#endif
LPBYTE pData = (LPBYTE)pDropFile + sizeof(DROPFILES);
int iSize = sizeof(szFiles);
::CopyMemory(pData,szFiles,sizeof(szFiles));
::GlobalUnlock(hData);
::SetClipboardData(CF_HDROP,hData);
::CloseClipboard();
}
}
void CTestMFCView::OnEditPastehdrop()
{
// TODO: Add your command handler code here
if(::OpenClipboard(m_hWnd))
{
//CListBox* pClistBox = new CListBox;
HDROP hDrop = (HDROP)::GetClipboardData(CF_HDROP);
if(NULL != hDrop)
{
//获得剪切板上文件名称得数目
int iCount = ::DragQueryFile(hDrop,(UINT)-1,NULL,0);
TCHAR szFile[MAX_PATH];
CString strFileName,strTemp;
if(iCount)
{
for(int i=0;i<iCount;i++)
{
::DragQueryFile(hDrop,i,szFile,MAX_PATH);
strTemp.Format(_T("%s "),szFile);
//pClistBox->AddString(szFile);
strFileName += strTemp;
}
}
CClientDC dc(this);
RECT rect;
::GetClientRect(m_hWnd,&rect);
dc.DrawText(strFileName,&rect,DT_CENTER);
}
//delete pClistBox;
::CloseClipboard();
}
}
4.使用自定义剪切板格式,只要注册时 名称相同,得到的格式id就相同,粘贴时,需要知道拷贝的长度,所以可以在自定义格式的结构中加入文件长度的成员。
void CTestMFCView::OnEditCopyprivatedata()
{
// TODO: Add your command handler code here
UINT nID = ::RegisterClipboardFormat(_T("MyStyle"));
if(::OpenClipboard(m_hWnd))
{
::EmptyClipboard();
TCHAR szText[] = _T("This is my style!");
HANDLE hData = ::GlobalAlloc(GHND,sizeof(szText));
TCHAR* pText = (TCHAR*)::GlobalLock(hData);
::CopyMemory(pText,szText,sizeof(szText));
::GlobalUnlock(hData);
::SetClipboardData(nID,hData);
::CloseClipboard();
}
}
void CTestMFCView::OnEditPasteprivatedata()
{
// TODO: Add your command handler code here
if(::OpenClipboard(m_hWnd))
{
HANDLE hData = ::GetClipboardData(::RegisterClipboardFormat(_T("MyStyle"
)));
TCHAR* szText = (TCHAR*)::GlobalLock(hData);
CClientDC dc(this);
::TextOut(dc.m_hDC,0,0,szText,_tcslen(szText));
}
}
5.当调用SetClipBoardDat向剪切板中拷贝数据时,可以为每种格式调用一次该函数,这样在粘贴的时候就可以以多种方式进行粘贴了。以下是一些有用的函数
CountClipboardFormats:返回有效的格式总数
EnumClipboardFormats:枚举有效的格式
IsClipboardFormatAvailable:说明特定格式下数据是否有效
GetPriorityClipboardFormat:给定一个具有优先级的列表,说明哪个是可以首先使用的
6.使用Ole类来实现剪切板功能,Ole是完全基于Com的,所有的数据都是通过指向Com接口的指针调用方法来实现的.其次,Ole剪切板支持存储媒体而不是全局内存.MFC封装了两个类,可以用来实现剪切板功能COleDataSource和COleDataObject,以下是关于使用Ole的具体代码.
以下是使用内存来完成剪切板的操作的
void CTestMFCView::OnOleclipboardCopytext()
{
// TODO: Add your command handler code here
TCHAR szText[] = _T("Hello Old Clip board!");
HANDLE hData = ::GlobalAlloc(GHND,sizeof(szText));
LPTSTR pData = (LPTSTR)::GlobalLock(hData);
CopyMemory(pData,szText,sizeof(szText));
::GlobalUnlock(hData);
COleDataSource* pods = new COleDataSource;
pods->CacheGlobalData(CF_TEXT,hData);
pods->SetClipboard();
}
void CTestMFCView::OnOleclipboardPastetext()
{
// TODO: Add your command handler code here
TCHAR szText[MAX_PATH];
COleDataObject odo;
odo.AttachClipboard();
HANDLE hData = odo.GetGlobalData(CF_TEXT);
if(NULL != hData)
{
LPTSTR pData = (LPTSTR)::GlobalLock(hData);
int iLength = ::lstrlen(pData) ;
if(iLength < MAX_PATH)
{
_tcscpy_s(szText,sizeof(szText)/sizeof(TCHAR),pData);
}
::GlobalUnlock(hData);
::GlobalFree(hData);
}
DrawText(szText);
}
以下是使用临时文件作为媒体来操作剪切板的
void CTestMFCView::OnOleclipboardCopytextothermedia()
{
// TODO: Add your command handler code here
TCHAR szText[] = _T("Hello Ole MutiMedia Clip board!");
TCHAR szPath[MAX_PATH],szFileName[MAX_PATH];
::GetTempPath(sizeof(szPath)/sizeof(TCHAR),szPath);
::GetTempFileName(szPath,_T("tmp"),0,szFileName);
CFile file;
if(file.Open(szFileName,CFile::modeCreate|CFile::modeWrite))
{
file.Write(szText,sizeof(szText)+ 1);
file.Close();
// in STGMEDIUM, the lpszFileName must be WCHAR type
LPWSTR pwszFileName = (LPWSTR)::CoTaskMemAlloc(MAX_PATH*sizeof(TCHAR));
#ifdef _UNICODE
::lstrcpy(pwszFileName,szFileName);
#else
::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,szFileName,-1,pwszFileName,MAX_PATH);
#endif
FORMATETC fe = {CF_TEXT,NULL,DVASPECT_CONTENT,-1,TYMED_FILE};
STGMEDIUM stgm;
stgm.tymed = TYMED_FILE;
stgm.lpszFileName = pwszFileName;
stgm.pUnkForRelease = NULL;
COleDataSource* pods = new COleDataSource;
pods->CacheData(CF_TEXT,&stgm,&fe);
pods->SetClipboard();
}
}
void CTestMFCView::OnOleclipboardPastetextothermedia()
{
// TODO: Add your command handler code here
TCHAR szText[MAX_PATH];
STGMEDIUM stgm;
FORMATETC fe = {CF_TEXT,NULL,DVASPECT_CONTENT,-1,TYMED_FILE};
COleDataObject odo;
odo.AttachClipboard();
if(odo.GetData(CF_TEXT,&stgm,&fe) && stgm.tymed == TYMED_FILE)
{
TCHAR szFileName[MAX_PATH];
#ifdef _UNICODE
::lstrcpy(szFileName,stgm.lpszFileName);
#else
::WideCharToMultiByte(CP_ACP,0,stgm.lpszFileName,-1,szFileName,sizeof(szFileName)/sizeof(TCHAR),NULL,NULL);
#endif
CFile file;
if(file.Open(szFileName,CFile::modeRead))
{
DWORD dwSize = DWORD(file.GetLength());
if(dwSize < MAX_PATH)
{
file.Read(szText,(UINT)dwSize);
}
file.Close();
}
::ReleaseStgMedium(&stgm);
}
DrawText(szText);
}