VC 剪贴板操作


VC 剪贴板操作
2010年11月06日
  VC 剪贴板操作
  程序里用到了操作剪贴板的函数,而一直有个问题未能解决。有时会出现莫名其妙的异常。比如我把文本拷贝到剪贴板,之后我的编辑框竟然不能输入文本,即使可以输入,也是一推乱码。今天终于找到根源了。就是多了一句代码GlobalFree 害得我调试惨了。唉!感叹!忏悔一身的业障,才招来今日的遇事不顺!阿弥陀佛!
  MSDN里面说得很清楚了:
  After SetClipboardData is called, the system owns the object identified by the hMem parameter. The application can read the data, but must not free the handle or leave it locked. If the hMem parameter identifies a memory object, the object must have been allocated using the GlobalAlloc function with the GMEM_MOVEABLE and GMEM_DDESHARE flags. 
  我自作聪明调用了GlobalFree所以出现了意想不到的bug。
  一、设置剪贴板文本 /************************************************* *************************** 设置剪贴板文本 ************************************************** **************************/ bool SetClipBoardText(const TCHAR* text,HWND hWnd) { ASSERT(hWnd); //打开剪贴板 if ( !::OpenClipboard(hWnd) ) return false; //empties the clipboard and frees handles to data in the clipboard if ( !EmptyClipboard() ) { CloseClipboard(); return false; } //get text length int len=_tcslen(text); //After SetClipboardData is called, the system owns the object identified by the hMem parameter. //The application can read the data, but must not free the handle or leave it locked. If the //hMem parameter identifies a memory object, the object must have been allocated using the //GlobalAlloc function with the GMEM_MOVEABLE and GMEM_DDESHARE flags. HANDLE hClip=GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,(len +1)*sizeof(TCHAR)); if (hClip==NULL) { CloseClipboard(); return false; } //locks a global memory object and returns a pointer to the first byte of the object's memory block TCHAR* pBuf=(TCHAR*)GlobalLock(hClip); if (pBuf==NULL) { GlobalFree(hClip); CloseClipboard(); return false; } memcpy(pBuf,text,len*sizeof(TCHAR)); pBuf[len]=NULL; GlobalUnlock(hClip); if (NULL==SetClipboardData(CF_TEXT,hClip)) { GlobalFree(hClip); CloseClipboard(); return false; } CloseClipboard(); return true; }  二、获取剪贴板文本 #include  using namespace std; /************************************************* *************************** 获取剪贴板文本 ************************************************** **************************/ string GetClipBoardText(HWND hWnd) { ASSERT(hWnd); string ClipBoardText; //判断剪贴板的数据格式是否可以处理。 if (!IsClipboardFormatAvailable(CF_TEXT)) return ClipBoardText; //打开剪贴板。 if (!::OpenClipboard(hWnd)) return ClipBoardText; //获取数据 HGLOBAL hMem = GetClipboardData(CF_TEXT); if (hMem != NULL) { //获取字符串。 LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); if (lpStr != NULL) { ClipBoardText=lpStr; //释放锁内存 GlobalUnlock(hMem); } } //关闭剪贴板 CloseClipboard(); return ClipBoardText; }  三、获得剪贴板位图: //获得剪贴板位图 HBITMAP bitmap=(HBITMAP)GetClipboardData(CF_BITMAP);  四、复制位图到剪贴板 最简单的形式: void BitmapToClipboard(HBITMAP hBitmap) { ::OpenClipboard(NULL); ::EmptyClipboard() ; ::SetClipboardData(CF_BITMAP,hBitmap); ::CloseClipboard(); } 复制位图到剪贴板 复制一幅位图到剪贴板相当简单,需要记住的一个是如果位图需要调色盘, 你应当将调色盘也复制。 函数一:复制设备相关位图到剪贴板 CopyBitmapToClipboard()函数复制一幅DDB位图到剪贴板,如果提供调色盘它将 同时复制调色盘。注意在最后调用Detach()。这一点很重要,因为此时GDI对象 的物主已经传送至剪贴板。 // CopyBitmapToClipboard - Copies a device-dependent bitmap to clipboard // pWnd - Pointer to window that opens the clipboard // bitmap - The device-dependent bitmap // pPal - Pointer to logical palette - Can be NULL // NOTE - GDI objects are detached from bitmap & pPal // as the clipboard owns them after the copy void CopyBitmapToClipboard( const CWnd *pWnd, CBitmap& bitmap, CPalette* pPal ) { ::OpenClipboard(pWnd->GetSafeHwnd()); ::EmptyClipboard() ; if( pPal ) ::SetClipboardData (CF_PALETTE, pPal->GetSafeHandle() ) ; ::SetClipboardData (CF_BITMAP, bitmap.GetSafeHandle() ) ; ::CloseClipboard () ; bitmap.Detach(); if( pPal ) pPal->Detach(); } 函数二:复制设备无关位图到剪贴板 CopyDIBToClipboard()函数和CopyBitmapToClipboard()非常相似。内存句柄包 含了BITMAPINFO 和位图的位信息,通过GlobalAlloc()分配。 // CopyDIBToClipboard - Copies a device-dependent bitmap to clipboard // pWnd - Pointer to window that opens the clipboard // hDIB - Memory handle that contains BITMAPINFO & bitmap bits // pPal - Pointer to logical palette - Can be NULL // NOTE - GDI objects are detached from bitmap & pPal // as the clipboard owns them after the copy void CopyDIBToClipboard( const CWnd *pWnd, HGLOBAL hDIB, CPalette* pPal ) { ::OpenClipboard(pWnd->GetSafeHwnd()); ::EmptyClipboard(); if( pPal ) ::SetClipboardData (CF_PALETTE, pPal->GetSafeHandle() ) ; ::SetClipboardData (CF_DIB, hDIB ) ; ::CloseClipboard () ; bitmap.Detach(); if( pPal ) pPal->Detach(); }  五、更多剪贴板的操作,请看下面:(以下资料来自网络,找不到出处了)
  本文主要介绍了VC++/MFC中如下内容的剪贴板操作:
  1、文本内容的操作
  2、WMF数据的操作
  3、位图的操作
  4、设置使用自定义格式
  5、感知剪贴板内容的改变
  6、自动将数据粘贴到另一应用程序窗口
  一、文本内容的操作
  下面的代码示范了如何将文本内容复制到剪贴板(Unicode编码的先转化为ASCII):
  CString source;
  //文本内容保存在source变量中
  if( OpenClipboard() )
  {
  HGLOBAL clipbuffer;
  char * buffer;
  EmptyClipboard();
  clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1);
  buffer = (char*)GlobalLock(clipbuffer);
  strcpy(buffer, LPCSTR(source));
  GlobalUnlock(clipbuffer);
  SetClipboardData(CF_TEXT,clipbuffer);
  CloseClipboard();
  }
  下面的代码显示了如何从剪贴板上获得文本内容:
  char * buffer = NULL;
  //打开剪贴板
  CString fromClipboard;
  if ( OpenClipboard() )
  {
  HANDLE hData = GetClipboardData(CF_TEXT);
  char * buffer = (char*)GlobalLock(hData);
  fromClipboard = buffer;
  GlobalUnlock(hData);
  CloseClipboard();
  }
  二、WMF数据的操作
  在剪贴板上读写图象数据是非常有用的功能,并且实现起来也很简单。下面的代码显示了如何将扩展图元文件复制到剪贴板:
  if(OpenClipboard());
  {
  EmptyClipboard();
  //创建图元文件DC
  CMetaFileDC * cDC = new CMetaFileDC();
  cDC->CreateEnhanced(GetDC(),NULL,NULL,"the_name");
  //调用绘图例程
  //关闭CMetafileDC并获得它的句柄
  HENHMETAFILE handle = cDC->CloseEnhanced();
  //复制到剪贴板
  SetClipBoardData(CF_ENHMETAFILE,handle);
  CloseClipboard();
  //删除dc
  delete cDC;
  }
  下面的代码演示了从剪贴板获得图元文件并将其绘制到client DC上:
  if(OpenClipboard())
  {
  //获得剪贴板数据
  HENMETAFILE handle = (HENMETAFILE)GetClipboardData(CF_ENHMETAFILE);
  //显示
  CClientDC dc(this);
  CRect client(0,0,200,200);
  dc.PlayMetaFile(handle,client);
  //关闭剪贴板
  CloseClipboard();
  }
  三、位图的操作
  位图的操作稍微复杂一点,下面这个例子显示了如何在剪贴板保存位图:
  if(OpenClipboard())
  {
  EmptyClipboard();
  CBitmap * junk = new CBitmap();
  CClientDC cdc(this);
  CDC dc;
  dc.CreateCompatibleDC(&cdc);
  CRect client(0,0,200,200);
  junk->CreateCompatibleBitmap(&cdc,client.Width(),cl ient.Height());
  dc.SelectObject(junk);
  DrawImage(&dc,CString("Bitmap"));
  //复制数据到剪贴板
  SetClipboardData(CF_BITMAP,junk->m_hObject);
  CloseClipboard();
  delete junk;
  }
  下面的代码显示了如何从剪贴板上获得位图数据:
  if(OpenClipboard())
  {
  //获得剪贴板数据
  HBITMAP handle = (HBITMAP)GetClipboardData(CF_BITMAP);
  CBitmap * bm = CBitmap::FromHandle(handle);
  CClientDC cdc(this);
  CDC dc;
  dc.CreateCompatibleDC(&cdc);
  dc.SelectObject(bm);
  cdc.BitBlt(0,0,200,200,&dc,0,0,SRCCOPY);
  CloseClipboard();
  }
  四、设置并使用自定义格式
  使用RegisterClipboardFormat()函数,可以复制和粘贴任何你需要的数据类型。比如我们有以下一个数据类型:
  struct MyFormatData
  {
  long val1;
  int val2;
  };
  我们要把它复制到剪贴板,可以使用如下的代码:
  UINT format = RegisterClipBoardFormat("MY_CUSTOM_FORMAT");
  if(OpenClipboard())
  {
  MyFormatData data;
  data.val1 = 100;
  data.val2 = 200;
  HGLOBAL clipbuffer;
  EmptyClipboard();
  clipbuffer = GlobalAlloc(GMEM_DDESHARE, sizeof(MyFormatData));
  MyFormatData * buffer = (MyFormatData*)GlobalLock(clipbuffer);
  //保存到内存
  *buffer = data;
  //保存到剪贴板
  GlobalUnlock(clipbuffer);
  SetClipboardData(format,clipbuffer);
  CloseClipboard();
  }
  读取数据使用以下代码:
  UINT format = RegisterClipboardFormat("MY_CUSTOM_FORMAT");
  MyFormatData data;
  if(Openclipboard())
  {
  HANDLE hData =GetClipboardData(format);
  MyFormatData * buffer = (MyFormatData*)GlobalLock(hData);
  data = *buffer;
  GlobalUnlock(hData);
  CloseClipboard();
  }
  五、感知剪贴板内容的改变
  通过Windows消息可以感知剪贴板内容是否发生改变,代码如下:
  //In your initialization code call:
  SetClipboardViewer(); //将我们的程序添加到剪贴板观察链
  //In your message map add:
  ON_MESSAGE(WM_DRAWCLIPBOARD, OnClipChange) //添加Message handle
  //Which is declared as:
  afx_msg void OnClipChange();
  Finally implement:
  void CDetectClipboardChangeDlg::OnClipChange() 
  {
  CTime time = CTime::GetCurrentTime();
  SetDlgItemText(IDC_CHANGED_DATE,time.Format("%a, %b %d, %Y -- %H:%M:%S"));
  DisplayClipboardText();
  }
  六、自动将数据粘贴到另一应用程序窗口
  只需获得相应窗口的句柄,并发送一个消息就可以了:
  SendMessage(m_hTextWnd, WM_PASTE, 0, 0);
  六、推荐:
  狮姐的博客(狮子窝,学佛与灵魂之探究)
  大方广(学习传统文化)
  慈善点击(轻松一点,行善积德,何乐不为)
  电影《地球公民》(揭示不为人知的一面)  
  心向光明 远离邪淫(现世警钟,不可不看) 
  戒淫(上篇)(正淫节欲,戒除邪淫) 
  戒淫(中篇)(纵欲之乐,忧患随之)
  公民教育--命由我造

猜你喜欢

转载自kdyzi19u.iteye.com/blog/1363607