剪切板:系統維護的一個全局公共內存區域.每次只允許一個進程對其進行訪問。
剪切板操作方法如下:(MSDN上搜索Clipboard Operations)
1.打開剪切板
Bool OpenClipboard(HWND hWndNewOwner);
指定關聯到打開的剪切板的窗口句柄,傳入NULL表示關聯到當前任務。每次只允許一個進程打開並訪問。
每打開一次就要關閉,否則其他進程無法訪問剪切板。
2.清空剪切板
Bool EmptyClipboard(void)
寫入前必須先清空,得到剪切板占有權
3.分配內存
HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);
在堆上動態分配以字節為單位的內存區域。成功則指向該內存,失敗NULL。參數:1.分配內存屬性, 2.分配的大小
4.鎖定內存
LPVOID GlobalLock(HGLOBAL hMem);
鎖定由GlobalAlloc分配的內存,並將內存對象的鎖定計數器+1,成功返回指向內存對象起始地址的指針。失敗NULL
系統為每個全局內存對象維護一個鎖定計數器,初始為0,GlobalLock使計數器+1,GlobalUnLock計數器-1.一旦計數器值大於0,
這塊內存區域將不允許被移動或刪除,只有當為0時,才解除對這塊內存的鎖定。如果分配時GMEM_FIXED屬性,計數器一直為0
5.設置剪切板
HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
執行成功,返回數據句柄,否則返回NULL
6.解除鎖定
BOOL GlobalUnlock(HGLOBAL hMem);
將GlobalAlloc分配的屬性為GMEM_MOVEABLE的內存對象計數器-1.
7.關閉剪切板
Bool CloseClipboard(void);
必須關閉剪切板其他進程才能使用剪切板,且關閉后當前進程就不能寫入數據。
8.獲取剪切板數據
HANDLE GetClipboardData(UINT uFormat);
執行成功,返回數據句柄,否則返回NULL數據格式,指定格式的數據的句柄
一:UINT uFormate格式說明:標准剪貼簿數據格式
Windows支持不同的預先定義剪貼簿格式, 這些格式在WINUSER.H定義成以CF為前綴的標識符。
■三種能夠儲存在剪貼簿上的文字數據型態:
①CF_TEXT 以NULL結尾的ANSI字符集字符串。它在每行末尾包含一個carriage return和linefeed字符,這是最簡單的剪貼簿數據格式。
②CF_OEMTEXT 含有文字數據(與CF_TEXT類似)的內存塊。但是它使用的是OEM字符集。
③CF_UNICODETEXT 含有Unicode文字的內存塊。與CF_TEXT類似,它在每一行的末尾包含一個carriage return和linefeed字符,以及一個NULL字符(兩個0字節)以表示數據結束。CF_UNICODETEXT只支援Windows NT。
■兩種附加的剪貼簿格式、但是它們不需要以NULL結尾,因為格式已經定義了數據的結尾。
①CF_SYLK 包含Microsoft 「符號連結」數據格式的整體內存塊。這種格式用在Microsoft的Multiplan、Chart和Excel程序之間交換數據,它是一種ASCII碼格式。
②CF_DIF 包含數據交換格式(DIF)之數據的整體內存塊。用於把數據送到VisiCalc電子表格程序中。這也是一種ASCII碼格式
■下面三種剪貼簿格式與位圖有關。所謂位圖就是數據位的矩形數組
①CF_BITMAP 與設備相關的位圖格式。位圖是通過位圖句柄傳送給剪貼簿的。
②CF_DIB 定義一個設備無關位圖的內存塊。
③CF_PALETTE 調色盤句柄。
■下面是兩個metafile格式、metafile就是一個以二進制格式儲存的畫圖命令集
①CF_METAFILEPICT 以舊的metafile格式存放的「圖片」 。
②CF_ENHMETAFILE 增強型metafile(32位Windows支持的)句柄。
■最后介紹幾個混合型的剪貼簿格式:
CF_PENDATA與Windows的筆式輸入擴充功能聯合使用。
CF_WAVE聲音(波形)文件。
CF_RIFF使用資源交換文件格式(Resource Interchange File Format)的多媒體數據。
CF_HDROP與拖放服務相關的文件列表。
二:UINT uFlags格式說明:內存屬性
GMEM_FIXED
分配一塊固定的內存區域,不允許系統移動,這時返回值是一個指針。
GMEM_MOVEABLE
分配一塊可移動的內存區域,實際上內存塊在物理內存中是不可移動的,這里的可移動指的是在應用程序的默認邏輯堆內可以移動。返回值是內存對象的句柄。可以通過調研GlobalLock()函數將一個句柄轉化為一個指針,這個標志不能喝GMEM_FIXED 同時使用
GMEM_ZEROINT
初始化內存對象為全0,如果不用這個標志,內存對象將為不確定的內容
GHND
GMEM_MOVEABLE和GMEM_ZEROINT塊標志聯合使用,即可移動同時初始化為0
GPTR
GMEM_FIXED和GMEM_ZEROINT標志聯合使用,即不可移動同時初始化為0
1 void CMFC_TabCtrlDlg::SetClipBoardData_(CString strText) 2 { 3 /* 4 OpenClipboard打開剪切板:指定關聯到打開的剪切板的窗口句柄,傳入NULL表示關聯到當前任務。每次只允許一 5 個進程打開並訪問。每打開一次就要關閉,否則其他進程無法訪問剪切板。 6 EmptyClipboard清空剪切板:寫入前必須先清空,得到占有權 7 */ 8 if (::OpenClipboard(m_hWnd) &&::EmptyClipboard()) 9 { 10 //根據環境變量獲取數據長度 11 size_t cbStr = (strText.GetLength() + 1) * sizeof(TCHAR); 12 13 //在堆上動態分配以字節為單位的全局內存區域。成功則指向該內存,失敗NULL。參數:1.分配內存屬性,2.大小 14 HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, cbStr); 15 16 if (hMem == NULL) 17 { 18 //關閉剪切板,釋放剪切板所有權,關閉后就不能寫入數據 19 CloseClipboard(); 20 return; 21 } 22 23 //鎖定由GlobalAlloc分配的內存,並將內存對象的鎖定計數器+1;成功返回指向內存對象起始地址的指針。失敗NULL 24 LPTSTR lpDest = (LPTSTR)GlobalLock(hMem); 25 /* 26 系統為每個全局內存對象維護一個鎖定計數器,初始為0,GlobalLock使計數器+1, 27 */ 28 29 //拷貝數據到剪貼板內存。 30 memcpy_s(lpDest, cbStr, strText.LockBuffer(), cbStr); 31 strText.UnlockBuffer(); 32 33 //解除內存鎖定,將屬性為GMEM_MOVEABLE的內存對象計數器-1. 34 GlobalUnlock(hMem); 35 /* 36 GlobalUnLock計數器-1.一旦計數器值大於0,這塊內存區域將不允許被移動或刪除,只 37 有當為0時,才解除對這塊內存的鎖定。如果分配時GMEM_FIXED屬性,計數器一直為0 38 39 */ 40 41 //根據環境變量設置數據格式 42 UINT uiFormat = (sizeof(TCHAR) == sizeof(WCHAR))?CF_UNICODETEXT:CF_TEXT; 43 44 //設置數據到剪貼板。執行成功,返回數據句柄,否則返回NULL 45 if(SetClipboardData(uiFormat, hMem) == NULL); 46 { 47 CloseClipboard(); 48 return; 49 } 50 51 CloseClipboard(); 52 } 53 }
2.從剪切板內存獲取數據
1 void CMFC_TabCtrlDlg::GetClipBoardData_(void) 2 { 3 //if (IsClipboardFormatAvailable(CF_UNICODETEXT)) //判斷某種格式的數據是否可用 4 if(::OpenClipboard(m_hWnd)) 5 { 6 UINT uiFormat = (sizeof(TCHAR) == sizeof(WCHAR))?CF_UNICODETEXT:CF_TEXT; 7 8 ////執行成功,返回數據句柄,否則返回NULL。參數:1.數據格式,2.指定格式的數據的句柄 9 HGLOBAL hMem = GetClipboardData(uiFormat); 10 11 if (hMem != NULL) 12 { 13 //獲取UNICODE的字符串。 14 LPCTSTR lpStr = (LPCTSTR)GlobalLock(hMem); 15 if (lpStr != NULL) 16 { 17 SetDlgItemText(IDC_EDIT1, lpStr); 18 } 19 GlobalUnlock(hMem); 20 } 21 } 22 CloseClipboard(); 23 }