跟我一起玩Win32開發(21):複製&貼上&剪貼簿操作
我要提醒一下大家,看了我的博文學到的知識,千萬不要用於實際開發,不然你會被你的上司罵:“媽的,這些東西哪來的,從來沒有人這樣做過。”不信你試試,腦細胞被凍結的經理或者技術總監們肯定會這樣說的。
如果是一些有X年工作經驗(X永遠不可能大於100)的程式設計師肯定會說:“你怎麼這麼不成熟?”你如果被別人這麼說之後,不知道你會不會很傷心,或者很生氣?
我呢,曾經被N個人這樣教育過,不過你猜猜我當時的心情,我非常高興,喜悅。為什麼呢?
你不妨想想,當一個人說你不成熟的時候,你說他其實在說什麼,他其實是在說他自己很成熟,就因為他自己熟得快腐爛了,滿身惡臭,才會顯得你不成熟,仔細想想,是不是這個事兒?
那麼,成熟到底好不好呢?我相信小學生都有這樣的常識,當一個果子熟透了的時候,會怎麼樣?它會從樹枝上高空墜落,然後狠巴巴地摔到地上,粉身碎骨。呵呵,所以,你現在明白了吧,當別人說我不成熟的時候,我會非常高興,我心裡想:“快了快了,你快完蛋了。”
----------------------------------------------------------------------------------------------------------------
好,牛皮吹完,樂一樂。下面開始幹正事,今天咱們來認識一下怎麼操作貼上板,即複製和貼上資料。我不知道大家看不看恐怖片,反正我現在不得不嚇你一回。這個貼上板的操作,其實挺痛苦的,所以,如果在實際開發中,我肯定用CLR的類來弄,是的,這是我的做事原則,哪種方法最簡單就用哪種,這叫什麼?效率最大化,只有閒著沒事幹的人才會簡單問題複雜化。
不過呢,畢竟這裡咱們要了解一下在Win32下操作貼上板的,所以呢,我還是用API來解決,至於CLR方法,相信你比我更會用,你不信算了,反正我信了,我不是菜鳥,但我是菜鶴。
讀寫貼上板就像我們上廁所一樣,首先開啟廁所門(呼叫OpenClipboard函式),然後大動作(SetClipboardData或GetClipboardData),幹完了出來,關上廁所門(呼叫CloseClipboard)。
我說它有點痛苦是因為操作的時睺,與我們平常讀寫一些資料不同,資料寫入到剪貼簿後就由作業系統接管了,期間你不能任意讀寫,就像公共廁所是提供給你用的,你不能在裡面給人家裝修,拆掉人家的東西。
一、複製資料
我這裡就不弄太複雜了,就複製一串文字吧,這也常用。先看看程式碼。
//複製內容 //開啟剪貼簿 OpenClipboard(hdlg); //清空剪貼簿 EmptyClipboard(); //向剪貼簿中放東西 HWND hedt = GetDlgItem(hdlg, IDC_EDTCPY); WCHAR ntext[100]; SendMessage(hedt, WM_GETTEXT, (WPARAM)100, (LPARAM)ntext); //分配記憶體 HGLOBAL hgl = GlobalAlloc(GMEM_MOVEABLE, 100 * sizeof(WCHAR)); LPWSTR lpstrcpy = (LPWSTR)GlobalLock(hgl); memcpy(lpstrcpy, ntext, 100 * sizeof(WCHAR)); GlobalUnlock(hgl); SetClipboardData(CF_TEXT, lpstrcpy); //關閉剪貼簿 CloseClipboard();
大家看到,在開啟剪貼簿後,要先清空一下,呼叫EmptyClipboard函式,把裡面的東西清了,才能放東西進去。但是我們不能直接用SetClipboardData設定資料,不然你試試,會失敗,因為資料雖然是我們放進去的,但他歸系統管,雖然我們的房子是自己買的,但也歸小區物業公司管理。
因此,我們要通過記憶體拷貝來完成,GlobalAlloc函式分配全域性記憶體塊,不過標誌引數要用GMEM_MOVEABLE,為什麼,看MSDN怎麼說的。
你可能會問,SetClipboardData中的引數是HANDLE型別的,為什麼不用轉換就能與
If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the
data until the CloseClipboard function is called. (The memory must be unlocked before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag.
這段話不知道你看懂了沒有,反正我看不懂,很難翻譯,乾脆不譯了。就是這段話告訴了我們,用GlobalAlloc分配記憶體時要用GMEM_MOVEABLE標誌。既然記憶體是動的(當然實體記憶體是固定的),那我們在拷貝前當然要把它鎖定,拷貝完了再解鎖,防止這塊記憶體被外星人意外修改了。
二、貼上資料
複製完了,就貼上了。
else if(LOWORD(wParam) == IDC_BTNPAST)
{
HWND hedtPas = GetDlgItem(hdlg, IDC_EDTPAST);
OpenClipboard(hdlg);
//判熂是否為文字內容
if(IsClipboardFormatAvailable(CF_TEXT))
{
//取出資料
HGLOBAL hg = GetClipboardData(CF_TEXT);
//鎖定記憶體塊
LPWSTR wstr = (LPWSTR)GlobalLock(hg);
if(wstr != NULL)
{
SendMessage(hedtPas, WM_SETTEXT, NULL, (LPARAM)wstr);
}
GlobalUnlock(hg);
}
CloseClipboard();
}
這裡幹嗎要用IsClipboardFormatAvailable來檢測一下剪貼簿中是不是CF_TEXT格式的資料呢?因為在你複製了文字後,有可能在這期間其他程式把其他資料放到剪貼簿上了,所以,要檢查一下好,謹慎一點總是沒有錯的。
也許你會問,GetClipboardData不是返回HANDLE型別嗎?怎麼可以賦給HGLOBAL型別的變數而不用轉換呢,你把開對應標頭檔案看看就懂了,HGLOBAL就是HANDLE。
好了,就這樣吧,只要你簡單瞭解操作過程就夠了,不必深究,呵呵,因為有比這更簡單的方法。