window剪切板操作

来源:互联网 发布:马尔科夫值迭代算法 编辑:程序博客网 时间:2024/05/22 11:51

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);
}