剪贴板是Windows中系统级的堆空间,系统中任何一个应用程序对剪贴板都有访问权,可以通过剪贴板消息和使用剪贴板API来读写
剪贴板内容。
正在装载数据……
因此使用剪贴板不仅可以在同一个应用程序内交互数据,也可以在不通应用程序之间交互数据。尤其是在不通应用程序之间交互时
,应用程序往往需要对剪贴板内容的变化做到实时感知,即应用程序要能监视剪贴板内容的变化。
Windows应用是消息驱动的,同理当剪贴板内容发生变化时,Windows提供了剪贴板变化消息,因此要实时感知剪贴板内容的变化,
关键是应用程序要能响应和处理Windows触发的剪贴板变化消息。
第一步,要将窗口注册为Clipboard
Viewer
需要首先解释两个概念:Clipboard Viewer和Clipboard
Viewer Chain。
Clipboard
Viewer是一个需要取得并显示剪贴板内容的窗口,通过Clipboard
Viewer这个机制,应用程序可以在不影响剪贴板内容的情况下获取剪贴板的变化消息。Clipboard
Viewer可以显示系统定义的标准格式的剪贴板内容,也可以显示应用自定义的私有数据格式的内容。通过调用函数
SetClipboardViewer将窗口注册为Clipboard
Viewer。
Clipboard Viewer Chain是保存Clipboard
Viewer窗口以及他们之间的前后向关系的一个Windows系统链表,当一个窗口注册为Clipboard
Viewer后,他会被加入Clipboard Viewer
Chain,并得到链表中下一个Viewer窗口的句柄,该句柄必须保存以在响应消息时使用,该句柄的作用在下文说明。Windows正是通
过Clipboard
Viewer Chain保证了所有Clipboard
Viewer能接收和响应剪贴板变化消息。
第二步,响应剪贴板变化消息,判断和取出剪贴板内容
在消息响应里必须正确处理两个消息:WM_DRAWCLIPBOARD和WM_CHANGECBCHAIN。
当剪贴板内容发生变化时,Windows将触发WM_DRAWCLIPBOARD消息,并将该消息送给Clipboard Viewer
Chain的第一个窗口。每一个Clipboard
Viewer窗口,包括第一个窗口在响应和处理该消息后,必须根据其保存的链表中的下一个窗口的句柄将该消息发送给下一个
Clipboard
Viewer窗口。窗口可以在该消息中取出剪贴板内容,并判断是否是该窗口增在监视的内容,如果是就进行相应的处理。
当某个Clipboard
Viewer窗口注销时,系统将触发WM_CHANGECBCHAIN,并将该消息送给Clipboard Viewer
Chain的第一个窗口。每一个窗口必须处理该消息。
第三步,将窗口从Clipboard Viewer
Chain中注销
当窗口不再需要监视剪贴板变化消息,或窗口要关闭时,必须调用ChangeClipboardChain函数将窗口从Clipboard Viewer
Chain中注销。注销后系统会触发WM_CHANGECBCHAIN消息,同WM_DRAWCLIPBOARD消息一样,该消息会给发送给Clipboard
Viewer
Chain的第一个窗口处理。下面代码示例当窗口被关闭时进行注销。
下面的代码片断给出了监视剪贴板中是否拷贝了URL地址的例子,如果剪贴板中的内容是URL地址,则将其显示在窗口界面上。为使
示例代码具有一般性,下面给出了一般Windows程序代码和基于MFC的代代码。其他语言要实现该功能可以参考Windows程序代码。两个
DEMO的完成代码请见附件。
Windows程序示例代码
LRESULT CALLBACK WndProc(HWND
hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
int wmId,
wmEvent;
PAINTSTRUCT
ps;
HDC
hdc;
unsigned int
anFormats[] =
{CF_TEXT};
unsigned
int nFormat;
switch (message)
{
//----------------------------------------------------------------
case WM_CREATE:
//将本窗口注册到Clipboard Viewer
Chain,
//并保存Clipboard Viewer
Chain中下一个窗口的句柄
hwndNextViewer = SetClipboardViewer(hWnd);
break;
case WM_CHANGECBCHAIN: //Clipboard
Viewer注销
//如果注销的Clipboard
Viewer窗口是本窗口的下一个窗口,
//则修改本窗口保存的下一个窗口句柄,
//否则将该消息传递到Clipboard Viewer
Chain的下一个窗口
if ((HWND) wParam == hwndNextViewer)
hwndNextViewer = (HWND) lParam;
else if (hwndNextViewer != NULL)
SendMessage(hwndNextViewer, message, wParam, lParam);
break;
case WM_DRAWCLIPBOARD:
//剪贴板内容变化
//触发ON_PAINT显示URL内容
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
//否则将该消息传递到Clipboard Viewer
Chain的下一个窗口
SendMessage(hwndNextViewer, message, wParam, lParam);
break;
case
WM_DESTROY:
//从Clipboard Viewer
Chain注销本窗口
ChangeClipboardChain(hWnd, hwndNextViewer);
PostQuitMessage(0);
break;
//----------------------------------------------------------------
case
WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu
selections:
switch
(wmId)
{
case
IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX,
hWnd,
(DLGPROC)About);
break;
case
IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam,
lParam);
}
break;
case
WM_PAINT:
hdc = BeginPaint(hWnd,
&ps);
//判断剪贴板中的内容是否为URL地址,如是则显示
nFormat =
GetPriorityClipboardFormat(anFormats,sizeof(anFormats));
if(nFormat ==
CF_TEXT)
{
OpenClipboard(hWnd);
HGLOBAL hMem = GetClipboardData(nFormat);
LPTSTR lpstr = (LPTSTR)GlobalLock(hMem);
if(strstr(lpstr,"http://") != NULL
||
strstr(lpstr,"ftp://") != NULL
||
strstr(lpstr,"file://") !=
NULL)
{
RECT
rt;
GetClientRect(hWnd,
&rt);
DrawText(hdc, lpstr, -1, &rt,
DT_LEFT);
}
GlobalUnlock(hMem);
CloseClipboard();
}
EndPaint(hWnd,
&ps);
break;
default:
return DefWindowProc(hWnd, message, wParam,
lParam);
}
return
0;
}
MFC程序示例代码
首先要映射以下消息和继承以下函数
afx_msg void
OnChangeCbChain(HWND hWndRemove, HWND
hWndAfter);
afx_msg void
OnDrawClipboard();
afx_msg void
OnDestroy();
virtual void
OnInitialUpdate();
void
CMonitorUrlView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
m_pListCtrl =
&GetListCtrl();;
m_pListCtrl->SetExtendedStyle(LVS_EX_FULLROWSELECT
|
LVS_EX_GRIDLINES
|
LVS_EX_TRACKSELECT
|
LVS_EX_TWOCLICKACTIVATE
|
LVS_EX_UNDERLINECOLD);
m_pListCtrl->ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
m_pListCtrl->InsertColumn(0, "URL",LVCFMT_LEFT,600,1);
//将本窗口注册到Clipboard
Viewer Chain,
//并保存Clipboard Viewer
Chain中下一个窗口的句柄
m_hwndNextViewer = SetClipboardViewer();
}
void CMonitorUrlView::OnDestroy()
{
CListView::OnDestroy();
//从Clipboard Viewer
Chain注销本窗口
ChangeClipboardChain(m_hwndNextViewer);
}
//Clipboard Viewer注销
void
CMonitorUrlView::OnChangeCbChain(HWND hWndRemove, HWND hWndAfter)
{
//如果注销的Clipboard
Viewer窗口是本窗口的下一个窗口,
//则修改本窗口保存的下一个窗口句柄,
CView::OnChangeCbChain(hWndRemove,hWndAfter);
if(hWndRemove ==
m_hwndNextViewer)
m_hwndNextViewer = hWndAfter;
}
//剪贴板内容变化,判断剪贴板中的内容是否为URL地址,如是则显示
void
CMonitorUrlView::OnDrawClipboard()
{
CView::OnDrawClipboard();
unsigned int
anFormats[] =
{CF_TEXT};
unsigned
int nFormat =
GetPriorityClipboardFormat(anFormats,sizeof(anFormats));
if(nFormat ==
CF_TEXT)
{
HGLOBAL
hMem;
OpenClipboard();
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();
}
}
转载于:https://www.cnblogs.com/boneking/archive/2008/11/20/1337809.html