windows 剪贴板监控

迅雷下载或者旋风下载都有一个很有意思的剪贴板监控功能,当你打开剪贴板监控时,如果你复制了一个下载的URL,这两个程序都会弹出来下载框来让你去下载,显得很智能,昨天发现灵格斯词霸也有个剪贴板取词功能。

上个月写了个智能注册表定位器,输入一段注册表字符串,能为你打开注册表编辑器并定位到相应的注册表位置,有个哥么说想智能点,当我复制注册表字符串时,给我自动拷贝到输入框去啊,后来就研究了一下剪贴板监控,发现还是蛮简单的,原来这一切,微软都给我们想好了,:-)。

 

这是智能注册表定位器的外观

 windows 剪贴板监控_第1张图片

 

首先你要把一个窗口句柄传到windows的剪贴板监听链中,使用API:SetClipboardViewer,这样在用户复制或者剪切时,Windows会给我们的窗口发送一个WM_DRAWCLIPBOARD消息。而且,当有其他程序加入或者退出这个监听者链表时,Windows会给我们的窗口发送一个WM_CHANGECBCHAIN消息。注意:当自己的窗口接收到这两个消息时,应该使用SendMessage函数来把消息传送给下一个监听者。

m_hNextClipboard = ::SetClipboardViewer(GetSafeHwnd());调用该API会返回下一个监听的窗口句柄,这个要保存下来,等下有用。

我下面的说明都是以MFC为例的,SDK里面怎么做,其实是类似的,我就不加说明了,我也没试过,但是原理是一样的。

然后映射两个消息:ON_WM_CHANGECBCHAIN() 和 ON_WM_DRAWCLIPBOARD()

头文件里面添加如下两个消息函数声明:

afx_msg void OnChangeCbChain(HWND hWndRemove, HWND hWndAfter);

afx_msg void OnDrawClipboard();

WM_CHANGECBCHAIN消息的处理,代码如下:

void CTClipboardMonDlg::OnChangeCbChain(HWND hWndRemove, HWND hWndAfter) { CDialog::OnChangeCbChain(hWndRemove, hWndAfter); if (m_hNextClipboard == hWndRemove) m_hNextClipboard = hWndAfter; else if (m_hNextClipboard) ::SendMessage(m_hNextClipboard, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, (LPARAM)hWndAfter); }

当有其他程序加入或者退出windows剪贴板监控链时,你会收到此消息,两个参数hWndRemove正要移出剪贴板监听链的窗口句柄,hWndAfter是移出监听链的窗口句柄的下一个监听窗口句柄,此时你要处理两件事情,如果退出的窗口句柄刚好是当前监听窗口的下一个句柄,则把hWndAfter赋值给m_hNextClipboard,保持整个监听链的联通,如果不是的话则给m_hNextClipboard发送一个相同的WM_CHANGECBCHAIN消息,最终目的也是保持整个监听链的联通性。这是属于一个规范的问题,试想如果有一个程序不这样做,则会造成监听链断裂,某些加入了监听链的窗口就会收不到系统发送的剪贴板消息了(原因是因为系统只给剪贴板链的头发送ON_WM_DRAWCLIPBOARD()消息,然后每个窗口负责给后面剪贴板窗口链上的窗口发送ON_WM_DRAWCLIPBOARD()消息,如果你没有正确处理ON_WM_CHANGECBCHAIN消息,会造成某个窗口不能更新自己的下一个监听链窗口句柄,整个链就断了,链在它之后的窗口就收不到剪贴板变化消息了)。

ON_WM_DRAWCLIPBOARD消息处理,代码如下:

void CTClipboardMonDlg::OnDrawClipboard() { CDialog::OnDrawClipboard(); HGLOBAL hClipboardData; // 如果观看链中在当前程序下面存在下一个程序的话 // 就传递一个WM_DRAWCLIPBOARD 消息给它 if(m_hNextClipboard) ::SendMessage(m_hNextClipboard, WM_DRAWCLIPBOARD, 0, 0); // 打开剪贴板 ::OpenClipboard(GetSafeHwnd()); // 获得剪贴板内容的全局句柄,剪贴板内容格式限制为CF_TEXT 文本格式 hClipboardData = GetClipboardData(CF_TEXT); // 锁定全局句柄的地址,并赋给CString 型变量m_strContent CString m_strContent = (char *)(GlobalLock(hClipboardData)); // 将m_strContent 的内容在编辑框里显示出来 SetDlgItemText(IDC_EDIT_CLIP, m_strContent); // 取消锁定 GlobalUnlock(hClipboardData); // 关闭剪贴板 ::CloseClipboard(); unsigned int anFormats[] = {CF_TEXT, CF_HDROP}; unsigned int nFormat = GetPriorityClipboardFormat(anFormats, sizeof(anFormats)); if(nFormat == CF_TEXT) { HGLOBAL hMem; ::OpenClipboard(GetSafeHwnd()); if(hMem = ::GetClipboardData(CF_TEXT)) { LPTSTR lpszText = (LPTSTR)::GlobalLock(hMem); CString strURL = lpszText; strURL = strURL.SpanExcluding("/r/n"); if(strURL.Left(7).CompareNoCase("http://") == 0 || strURL.Left(6).CompareNoCase("ftp://") == 0 || strURL.Left(7).CompareNoCase("file://") == 0) { //m_pListCtrl->InsertItem(0,lpszText); } ::GlobalUnlock(hMem); } ::CloseClipboard(); } else if (nFormat == CF_HDROP) { HGLOBAL hMem; CString cstrInfo; char szFileName[MAX_PATH]; ::OpenClipboard(GetSafeHwnd()); if(hMem = ::GetClipboardData(CF_HDROP)) { UINT FileNumber = ::DragQueryFile((HDROP)hMem, -1, NULL, 0); //得到文件数量 for (int i = 0; i < FileNumber; i++) { //获得路径及文件名 ::DragQueryFile((HDROP)hMem, i, szFileName, sizeof(szFileName)); cstrInfo = cstrInfo + szFileName; cstrInfo = cstrInfo + "/r/n"; } SetDlgItemText(IDC_EDIT_CLIP, cstrInfo); } ::CloseClipboard(); } }

打开剪贴板,获取数据的方法这里就不说明了,我这里只想强调的是,一定要给监听链上的下一个窗口发送一个相同的ON_WM_DRAWCLIPBOARD消息,否则会怎么样,你可以自己写个程序试试。

在窗口销毁时,应该使这个窗口退出windwos剪贴板监控链,使用API:ChangeClipboardChain,传入调用SetClipboardViewer时的句柄。

附录

源代码下载:

http://download.csdn.net/source/1227140

 

我在网上找了一些剪贴板的API,可以去查查MSDN,嘿嘿,你想监控啥类型的数据就自己去编程实现啦。

(一)ChangeClipboardChain
将剪贴的连接从一个句柄转到下一个句柄。
BOOL ChangeClipboardChain(
HWND hWndRemove, // handle to window to remove
HWND hWndNewNext // handle to next window
);
(1)hWndRemove表示第一个窗口的句柄(断开)。
(2)hWndNewNext表示第二个窗口的句柄(连接)。
注意,在使用之前应该使用SetClipboardViewer事先进行窗口句柄的连接。
(二)CloseClipboard
关闭剪贴板。
BOOL CloseClipboard(VOID)//VOID意思是空白。
本函数没有参数,事先应该用OpenClipboard函数打开过剪贴板。
(三)CountClipboardFormats
不管剪贴板是什么格式,全部转化为数据格式。
int CountClipboardFormats(VOID)
本函数没有参数。
(四)EmptyClipboard
清空剪贴板。
BOOL EmptyClipboard(VOID)
本函数没有参数。
(五)EnumClipboardFormats
使剪贴板内的格式转变成指定格式。
UINT EnumClipboardFormats(
UINT format // specifies a known available clipboard format
);
其中format表示的是将要转化成的格式。该参数的意义可参照后面。
(六)GetClipboardData
获取剪贴板内的数据。
HANDLE GetClipboardData(
UINT uFormat // clipboard format
);
其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
(七)GetClipboardFormatName
获取剪贴板内数据格式的名称。
int GetClipboardFormatName(
UINT format, // clipboard format to retrieve
LPTSTR lpszFormatName, // address of buffer for name
int cchMaxCount // length of name string in characters
);
(1)format表示的意义同前,应该是不事先规定格式;
(2)lpszFormatName表示的是格式名称地址;
(3)cchMaxCount剪贴板内数据的长度。
(八)GetClipboardOwner
获取当前剪贴板是属于哪一个窗口的句柄。
HWND GetClipboardOwner(VOID)
返回那个窗口的句柄。
(九)GetClipboardSequenceNumber
返回剪贴板序号。
DWORD GetClipboardSequenceNumber(VOID)
(十)GetClipboardViewer
返回剪贴板属于窗口的句柄。
HWND GetClipboardViewer(VOID)
(十一)GetOpenClipboardWindow
返回打开剪贴板的那个窗口句柄。
HWND GetOpenClipboardWindow(VOID)
(十二)GetPriorityClipboardFormat
int GetPriorityClipboardFormat(
UINT *paFormatPriorityList, // address of priority list
int cFormats // number of entries in list
);
(十三)IsClipboardFormatAvailable
判断剪贴板的格式。
BOOL IsClipboardFormatAvailable(
UINT format // clipboard format
);
其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
(十四)OpenClipboard
打开剪贴板。
BOOL OpenClipboard(
HWND hWndNewOwner // handle to window opening clipboard
);
返回剪贴板的句柄。
(十五)RegisterClipboardFormat
注册新的剪贴板格式。
UINT RegisterClipboardFormat(
LPCTSTR lpszFormat // address of name string
);
lpszFormat新的剪贴板格式名称。
(十六)SetClipboardData
设置剪贴板内的数据。
HANDLE SetClipboardData(
UINT uFormat, // clipboard format
HANDLE hMem // data handle
);
uFormat表示的是要放进剪贴板数据的格式;
hMem表示数据的地址指针。
(十七)SetClipboardViewer
将剪贴板内容连接到窗口。
HWND SetClipboardViewer(
HWND hWndNewViewer // handle to clipboard viewer window
);
hWndNewViewer表示要连接到的那个窗口句柄。
上文中剪贴板格式Format的可选参数如下:
CF_BITMAP位图格式;
CF_DIB
CF_DIBV5
CF_DIF
CF_DSPBITMAP
CF_DSPENHMETAFILE
CF_DSPMETAFILEPICT
CF_DSPTEXT
CF_ENHMETAFILE
CF_GDIOBJFIRST
CF_GDIOBJLAST
CF_HDROP
CF_LOCALE
CF_METAFILEPICT
CF_OEMTEXT
CF_OWNERDISPLAY
CF_PALETTE
CF_PENDATA
CF_PRIVATEFIRST
CF_PRIVATELAST
CF_RIFF
CF_SYLK
CF_TEXT文本格式;
CF_WAVE音乐格式;
CF_TIFF
CF_UNICODETEXT

 

【END】

你可能感兴趣的:(windows,api,String,list,mfc,tiff)