📄 12. 剪贴簿.txt
字号:
不一定要使用else if叙述,它只用于保证hwndNextViewer为非NULL的值。hwndNextViewer的值为NULL时,执行这段程序代码的程序就是链中最后一个浏览器,而这是不可能的。
当程序快结束时,如果它仍然在剪贴簿浏览器链中,则必须从链中删除它。您可以在处理WM_DESTROY消息时呼叫ChangeClipboardChain来完成这项工作。
case WM_DESTROY :
ChangeClipboardChain (hwnd, hwndNextViewer) ;
PostQuitMessage (0) ;
return 0 ;
Windows还有一个允许程序获得第一个剪贴簿浏览器窗口句柄的函数:
hwndViewer = GetClipboardViewer () ;
一般来说不需要这个函数。如果没有目前的剪贴簿浏览器,则传回值为NULL。
下面是一个说明剪贴簿浏览器链如何工作的例子。当Windows刚启动时,目前剪贴簿浏览器是NULL:
剪贴簿浏览器:NULL
一个具有hwnd1窗口句柄的程序呼叫SetClipboardViewer。这个函数传回的NULL成为这个程序中的hwndNextViewer值:
目前剪贴簿浏览器:hwnd1
hwnd1的下一个浏览器:NULL
第二个具有hwnd2窗口句柄的程序呼叫SetClipboardViewer ,并传回hwnd1:
目前的剪贴簿浏览器:hwnd2
hwnd2的下一个浏览器:hwnd1
hwnd1的下一个浏览器:NULL
每三个程序(hwnd3)和第四个程序(hwnd4) 也呼叫SetClipboardViewer ,并且传回hwnd2和hwnd3:
目前的剪贴簿浏览器:hwnd4
hwnd4的下一个浏览器:hwnd3
hwnd3的下一个浏览器:hwnd2
hwnd2的下一个浏览器:hwnd1
hwnd1的下一个浏览器:NULL
当剪贴簿的内容发生变化时,Windows发送一个WM_DRAWCLIPBOARD消息给hwnd4,hwnd4发送消息给hwnd3,hwnd3发送消息给hwnd2,hwnd2发送消息给hwnd1,hwnd1传回。
现在hwnd2决定通过下列呼叫从链中删除自己:
ChangeClipboardChain (hwnd2, hwnd1) ;
Windows将wParam等于hwnd2、lParam等于hwnd1的WM_CHANGECBCHAIN消息发送给hwnd4。由于hwnd4的下一个测览器是hwnd3,所以hwnd4把这个消息传给hwnd3。现在hwnd3注意到wParam等于它的下一个测览器(hwnd2),所以将下一个浏览器设定为lParam (hwnd1)并且传回。这样工作就完成了。现在剪贴簿浏览器链如下:
目前剪贴簿浏览器:hwnd4
hwnd4的下一个浏览器:hwnd3
hwnd3的下一个浏览器:hwnd1
hwnd1的下一个浏览器:NULL
一个简单的剪贴簿浏览器
剪贴簿浏览器不一定要像Windows所提供的那样完善,例如,剪贴簿浏览器可以只显示一种剪贴簿数据格式。程序12-2中所示的CLIPVIEW程序是一种只能显示CF_TEXT格式的剪贴簿浏览器。
程序12-2 CLIPVIEW
CLIPVIEW.C
/*-------------------------------------------------------------------------
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,
TEXT ("Simple Clipboard Viewer (Text Only)"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
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)
{
static HWND hwndNextViewer ;
HGLOBAL hGlobal ;
HDC hdc ;
PTSTR pGlobal ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE:
hwndNextViewer = SetClipboardViewer (hwnd) ;
return 0 ;
case WM_CHANGECBCHAIN:
if ((HWND) wParam == hwndNextViewer)
hwndNextViewer = (HWND) 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 = (PTSTR) 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) ;
}
CLIPVIEW依上面所讨论的方法来处理WM_CREATE、WM_CHANGECBCHAIN、WM_DRAWCLIPBOARD和WM_DESTROY消息。WM_PAINT消息处理打开剪贴簿,并用CF_TEXT格式呼叫GetClipboardData。如果函数传回一个整体内存句柄,那么CLIPVIEW将锁定它,并用DrawText在显示区域显示文字。
处理标准格式(如Windows提供的那个剪贴簿一样)以外的数据格式的剪贴簿浏览器还需要完成一些其它工作,比如显示剪贴簿中目前所有数据格式的名称。使用者可以通过呼叫EnumClipboardFormats并使用GetClipboardFormatName得到非标准数据格式名称来完成这项工作。使用CF_OWNERDISPLAY数据格式的剪贴簿浏览器必须把下面四个消息送往剪贴簿数据的拥有者以显示该资料:
WM_PAINTCLIPBOARD
WM_SIZECLIPBOARD
WM_VSCROLLCLIPBOARD
WM_HSCROLLCLIPBOARD
如果您想编写这样的剪贴簿浏览器,那么必须使用GetClipboardOwner获得剪贴簿所有者的窗口句柄,并当您需要修改剪贴簿的显示区域时,将这些消息发送给该窗口。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -