(1)Windows下可运行任意个剪贴板查看器,但只有一个是“当前剪贴板查看器”,Windows只维护这个剪贴板查看器的窗口句柄,并在剪贴板内容改变时,通知它。
(2)当A程序注册为剪贴板查看器时,就成为当前查看器。Windows会把上个当前查看器B的窗口句柄交给A程序来保存。当A收到剪贴板消息时,要发送给查看器链中的下一个程序,即B的窗口过程。
12.3.2 剪贴板查看器函数和消息
(1)将程序加入剪贴板查看器链
static HWND hwndNextViewer;
case WM_CREATE:
hwndNextViewer =SetClipboardViewer(hwnd);//hwndNextViewer得保存下来,这是
//剪贴板消息的下一个接收者。
(2)WM_DRAWCLIPBOARD消息
①剪贴板内板改变时,会发送这消息给当前查看器(最新注册的那个)。
②剪贴板查看器链中的每个程序都应通用SendMessage把消息传给下一个查看器
(hwndNextViewer),直到hwndNextViewer为NULL。
③不要把WM_DRAWCLIPBOARD与WM_PAINTCLIPBOARD混为一谈
消息 |
消息发起者 |
WM_DRAWCLIPBOARD |
Windows自动发送的,通知查看器剪贴板内容发生了变化。 |
WM_PAINTCLIPBOARD |
查看器(即手动发送的),发给使用CF_OWNERDISP格式的程序 |
④WM_DRAWCLIPBOARD消息的处理
case WM_DRAWCLIPBOARD:
if(hwndNextViewer)SendMessage(hwndNextViewer,message,wParam,lParam);
InvalidateRect(hwnd,NULL,TRUE);
return 0;
(3)退出剪贴板查看器链:ChangeClipboardChain(hwnd,hwndNextViewer);
①当某个程序退出查看器链时,Windows会向当前查看器发送WM_CHANGECBCHAIN消息。
case WM_CHANGECBCHAIN: //wParam:要退出链的窗口句柄。lParam:它的下个剪贴板查看器 if((HWND)wParam == hwndNextViewer) //要退出的窗口w是不是我的下个查看器消息接收者? hwndNextViewer =(HWND)lParam; //如果是,将A的消息接收者(lParam)转到我的接收者。 else if(hwndNextViewer) //如果要退出的不是我的下个接收者,将退出消息转发下去。 SendMessage(hwndNextViewer,message,wParam,lParam); return 0;
②程序终止时,必须从查看器链退出中。
case WM_DESTROY:
ChangeClipboardChain(hwnd,hwndNextViewer);
PostQuitMessage(0);
(4)获得第一个剪贴板查看器(即当前查看器)的窗口句柄:hwndViewer= GetClipboardViewer();
12.3.3 一个简单的剪贴板查看器
①可实时感知剪贴板内容发生变化(eg.迅雷的下载地址监测)
②本程序只监测CF_TEXT的变化。
【ClipView程序】
效果图
/*------------------------------------------------------------ CLIPVIEW.C -- Simple Clipboard Viewer (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("ClipView"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Simple Clipboard Viewer(Text Only)"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; static HWND hwndNextViewer; HGLOBAL hGlobal; PTSTR pGlobal; switch (message) { case WM_CREATE: //加入剪贴板查看器链 hwndNextViewer = SetClipboardViewer(hwnd); return 0; case WM_CHANGECBCHAIN: //当有程序退出剪贴板查看器链时 //wParam:要退出查看器链的窗口句柄,lParam:它的下一个消息接收者。 if ((HWND)wParam == hwndNextViewer) //退出窗口是我的下个消息接收者? { hwndNextViewer = (HWND)lParam; //如果是,将该窗的下个消息接收者(lParam)转到我的名下。 } else if (hwndNextViewer) //要退出的不是我的下个接收者,则直接将退出消息向下通知出去。 SendMessage(hwndNextViewer, message, wParam, lParam); return 0; case WM_DRAWCLIPBOARD: //当剪贴板内容改变时,将消息通知下去。 if (hwndNextViewer) SendMessage(hwndNextViewer, message, wParam, lParam); InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); OpenClipboard(hwnd); #ifdef UNICODE hGlobal = GetClipboardData(CF_UNICODETEXT); #else hGlobal = GetClipboardData(CF_TEXT); #endif if (hGlobal != NULL) { pGlobal = GlobalLock(hGlobal); DrawText(hdc, pGlobal, -1, &rect, DT_EXPANDTABS); GlobalUnlock(hGlobal); } CloseClipboard(); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: //退出剪贴板查看器链 ChangeClipboardChain(hwnd, hwndNextViewer); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }