📄 见招拆招《windows程序设计》(十一) .txt
字号:
SendMessage (hwndNextViewer, message, wParam, lParam) ;
return 0 ;
不一定要使用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.ASM
;MASMPlus 代码模板 - 普通的 Windows 程序代码
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
include macro.asm
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
.DATA
szAppName TCHAR "ClipView",0
.DATA?
hInstance HINSTANCE ?
hwndNextViewer HWND ?
.CODE
START:
invoke GetModuleHandle,NULL
invoke WinMain,eax,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,0
WinMain proc hInst:DWORD,hPrevInst:DWORD,szCmdLine:DWORD,iCmdShow:DWORD
LOCAL wndclass :WNDCLASSEX
LOCAL msg :MSG
LOCAL hWnd :HWND
LOCAL hAccel:HACCEL
mov wndclass.cbSize,sizeof WNDCLASSEX
mov wndclass.style,CS_HREDRAW or CS_VREDRAW
mov wndclass.lpfnWndProc,offset WndProc
mov wndclass.cbClsExtra,0
mov wndclass.cbWndExtra,0
push hInst
pop wndclass.hInstance
invoke LoadIcon,hInst,addr szAppName
mov wndclass.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wndclass.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov wndclass.hbrBackground,EAX
lea eax,szAppName
mov wndclass.lpszMenuName,eax
mov wndclass.lpszClassName,eax
mov wndclass.hIconSm,0
invoke RegisterClassEx, ADDR wndclass
.if (eax==0)
invoke MessageBox,NULL,CTXT("This program requires Windows NT!"),szAppName, MB_ICONERROR
ret
.endif
invoke CreateWindowEx,NULL,
ADDR szAppName, ;window class name
CTXT("Simple Clipboard Viewer (Text Only)"),
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
hInst, ;program instance handle
NULL ;creation parameters
mov hWnd,eax
invoke ShowWindow,hWnd,iCmdShow
invoke UpdateWindow,hWnd
invoke LoadAccelerators,hInstance,addr szAppName
mov hAccel,eax
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hwnd:DWORD,uMsg:DWORD,wParam :DWORD,lParam :DWORD
LOCAL hGlobal:HGLOBAL
LOCAL hdc:HDC
LOCAL pGlobal:PTSTR
LOCAL ps:PAINTSTRUCT
LOCAL rect:RECT
.if uMsg == WM_CREATE
invoke SetClipboardViewer,hwnd
mov hwndNextViewer,eax
xor eax,eax
ret
.elseif uMsg == WM_CHANGECBCHAIN
mov eax,wParam
.if eax == hwndNextViewer
mov eax,lParam
mov hwndNextViewer,eax
.else
.if hwndNextViewer!=0
invoke SendMessage,hwndNextViewer, uMsg, wParam, lParam
.endif
.endif
xor eax,eax
ret
.elseif uMsg == WM_DRAWCLIPBOARD
.if hwndNextViewer != 0
invoke SendMessage,hwndNextViewer, uMsg, wParam, lParam
.endif
invoke InvalidateRect,hwnd, NULL, TRUE
xor eax,eax
ret
.elseif uMsg == WM_PAINT
invoke BeginPaint,hwnd,addr ps
mov hdc,eax
invoke GetClientRect,hwnd,addr rect
invoke OpenClipboard,hwnd
invoke GetClipboardData,CF_TEXT
mov hGlobal,eax
.if hGlobal != NULL
invoke GlobalLock,hGlobal
mov pGlobal,eax
invoke DrawText,hdc, pGlobal, -1, addr rect, DT_EXPANDTABS
invoke GlobalUnlock,hGlobal
.endif
invoke CloseClipboard
invoke EndPaint,hwnd,addr ps
xor eax,eax
ret
.elseif uMsg == WM_DESTROY
invoke ChangeClipboardChain,hwnd, hwndNextViewer
invoke PostQuitMessage,NULL
xor eax,eax
ret
.endif
invoke DefWindowProc,hwnd,uMsg,wParam,lParam
ret
WndProc endp
END START
运行结果
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获得剪切板所有者的窗口句柄,并当您需要修改剪切板的显示区域时,将这些消息发送给该窗口。
上面学习了剪切板的使用,最后,我这里还有一个创意提供给各位读者,有兴趣的可以在下面试验一下,这个是完全可以做到的,我用Delphi已经轻松的实现了。
现在的MP3容量越来越大,我在使用MP3听评书的时候发现了一个问题:拷贝进去的歌曲无法控制顺序,就是你选中N多歌曲,用拷贝粘贴的方式丢在MP3里面,播放出来的通常会混乱。“三顾茅庐”会排在“草船借箭”的后面。经过考察发现,歌曲的顺序是又声音文件在MP3 FAT中的顺序决定的。而FAT中排列的顺序是又拷贝进去的先后顺序决定的。拷贝进去的先后顺序则是剪切板中的顺序决定的。
下面的不说了。
--------------------------------------------------------------------------------
<<<上一篇 欢迎访问AoGo汇编小站:http://www.aogosoft.com
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -