分享
 
 
 

在应用程序中监视剪贴板的变化和内容

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

在应用程序中监视剪贴板的变化和内容

stove@vip.sina.com

剪贴板是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();

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有