跟我一起玩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。
好了,就这样吧,只要你简单了解操作过程就够了,不必深究,呵呵,因为有比这更简单的方法。