楼主 xmyjk | 
一、        何为WINDOWS剪贴板
      剪贴板是内存中的一块连续可变的区域,使得在各种应用程序之间,实现数据交换和共享信息。在WINDOWS的运行窗口,键入clipbrd,可以弹出官方的“剪贴簿查看程序”,实现对剪贴板内数据的监控。如下图:
 
 
    
      它的工作原理和流程,用通俗的语言举例,例如我们在IE中复制了网页中我们喜欢的一张图片,那描述这张图片的数据,将存放在剪贴板所在的特定内存区域中。一旦,我们在WORD中黏贴了这张图片,其实是WORD这个应用程序,访问了剪贴板,读取了这张图片的数据,然后乾坤大挪移到我们的WORD文档中进行储存。因为都是在内存中操作,所以速度非常快。  | 
2楼 xmyjk | 
二、WINDOWS剪贴板的数据格式
        既然:剪贴板是用于多个应用程序之间交换数据的,那存放在剪贴板的数据,是怎样的呢?
        ◆首先,由于存放在全局内存中,他们是公开的,应用程序们可以访问到的,并能交换所需的数据的。
        ◆其次,既然是公共的数据,那这些数据是有规范标准,是系统/用户已经预先设定格式,可以在不同的应用程序中进行交换。          例如我在网页复制了一段文字,既可以黏贴到记事本,也可黏贴到WORD。这说明了,这些数据是具有某些标准格式的,符合系统或程序间的设定的格式的。
         ◆进而,应用程序们都可以访问这些数据,那么,这些数据就必然是多元的。这就类似我们EXCEL的选择性黏贴。我们复制了单元格的一个公式,可以相对的黏贴这个公式,也可以仅黏贴值,还可以黏贴成图片。           这说明了,剪贴板中是可以同时存放多种格式的数据。我们移交给剪贴板的某个数据或消息,将在剪贴板内,自动以尽可能多种的以预设过数据格式进行呈现(取决于发起复制或剪贴的应用程序,不同应用程序不同上下文环境,处理数据格式范围不同,放进剪贴板数据格式类别也不同)。微软建议,当向剪贴板中放入数据时,首先放入最能描述所要传递的信息的数据,因为它所包含的信息最接近原始数据所要表达的信息。当从剪贴板中读取数据时,将按顺序枚举所有的数据格式,如果该数据格式在目标应用程序可用,则进行黏贴,否则继续枚举,直至有可用数据。          即使上传的数据结构自身就非常简单,就例如记事本的文本,剪贴板也能按照一些标准的预设格式,在内存中自动转换,生成多个剪贴板数据格式,以便多种程序的交换。就例如,我们仅仅在记事本复制了一小段文字,剪贴板也能按照如下几个格式,自动进行多样化存放。如下图:
 
              翻阅了下资料,有四类数据,剪贴板是自带转化功能的(剪贴板格式名称请参与下面的介绍):       (1)CF_TEXT、CF_UNICODETEXT与CF_OEMTEXT这三个文本格式相互之间;       (2)CF_METAFILEPICT和CF_ENHMETAFILE这两个图元文件相互之间;       (3)CF_BITMAP、CF_DIB与CF_DIBV5这三个位图数据格式相互之间;       (4)如果CF_DIB与CF_DIBV5的数据格式,将自动转化CF_PALETTE的数据格式,这个是单向的,反之不成立。              总之,剪贴板的数据是以多种数据格式进行呈现的。
          ◆最后,这些数据格式,是能被检索查询的,如果新的应用程序,需要新的数据格式,也可以使用API的RegisterClipboardFormat函数进行注册。这些已经预设或者注册过的,剪贴板存放过的数据格式,WINDOWS都会用一个长整形的编号,像字典一样,进行记录。通过这个编号,我们可以获取对应格式的数据。 对于WINDOWS系统初始的标准格式,这个编号是固定的,如下图:
 
                      如果是非系统标准格式的,允许运用RegisterClipboardFormat函数,用数据格式的名称,去注册这个格式,如果注册成功,将得到新的剪贴板数据格式对应的编号。如果重名,将直接返回已有这个数据格式名称对应的格式编号。  | 
3楼 xmyjk | 
三、获取剪贴板数据的套路和主要API的剪贴板函数简介
      一般而言,获取剪贴板数据的大致步骤如下(按需增减):         (一)用OpenClipboard打开剪贴板- Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
  参数hwnd:用来传递目前打开剪贴板的窗口的句柄。如果它修改了剪贴板内的数据,它就会成为剪贴板数据拥有窗口即ClipboardOwner,这样其他程序可以使用GetClipboardOwner去获取它。如果只是读取剪贴板内的数据,可以传递一个0&;如果要向剪贴板内写入数据,则必须指定有效的hwnd,否则不能成功调用SetClipboardData函数;              如果调用成功,将返回剪贴板的句柄。失败返回0。
       (二)EnumClipboardFormats加while来循环出一个可用的剪贴板格式- Declare Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long
  参数:wFormat表示剪贴板内已知可用的标准剪贴板格式或注册剪贴板格式的编号。在枚举的最开始,向函数传入0值,将返回第一个可用的剪贴板格式编号,将该返回值传给下一次函数调用,将得到下一个可用的剪贴板格式编号。以此循环,直至  返回0,可以枚举所有的可用的数据格式。
        或用IsClipboardFormatAvailable或GetPriorityClipboardFormat判断可用格式的存在- Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long
  参数:wFormat标准剪贴板格式或注册剪贴板格式的编号       如果剪贴板中存在相应格式的数据,则返回一个非0值否则返回0。       如果一个应用程序可以处理多种数据格式,运行传入数组的API函数:- Declare Function GetPriorityClipboardFormat Lib "user32" (lpPriorityList As Long, ByVal nCount As Long) As Long
  参数:lpPriorityList指向数组第一个元素的地址,这个数组中需按优先级别存放多个剪贴板格式编号;nCount表示数组内元素的个数;       如果剪贴板内存在一种或多种数组中列出的格式,则返回优先级别靠前的剪贴板格式编号;如果剪贴板内有数据但不包含数组中列出的任何一种格式,则返回-1;如果剪贴板为空,则返回0。- Dim arrf()
  - Dim f As Long
  - arrf = Array(49290, 49386, 1)
  - f = GetPriorityClipboardFormat(arrf(0), 3)
  (三)使用GetClipboardData获得剪贴板的内存块首地址- Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
  参数:wFormat表示将要取出的数据格式的编号;       如果成功,返回剪贴板中以指定格式存放的数据对象的句柄;失败,返回0;             一般而言,返回的内存对象的句柄,但是如果数据是一个图像格式,返回的将是一个GDI对象的句柄,例如,位图格式的返回位图GDI对象句柄,图元文件返回的是图元文件对象的句柄等。GDI对象另贴再解析。先按返回内存对象的句柄进行后续讲解。
        (四)用GlobalLock锁定剪贴板那内存块- Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  参数hMem是内存对象的句柄;       成功,返回值是内存对象所占用内存的第一个字节的内存地址;失败,返回0
       (五)GlobalSize可以用来获取该内存块的大小- Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
  参数hMem是内存对象的句柄;       成功,返回是内存对象所占用内存的字节长度,失败返回值0
        (六)用CopyMemory将二进制数据取出来并赋值给字节数组- Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  参数:Destination是要赋值的数组第一个元素的内存地址;Source是来源的第一个字节的内存地址;Length是要复制的数据的长度;
       (七)处理数据,转换数据格式等等        呵呵,这个就按需处理了。文本的,转换成文本数据,图片的,转换成图片,二进制的转换16进制翻译,等等
        (八)使用GlobalUnlock解除锁定- Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  参数hMem是内存对象的句柄;       被解锁,则返回0
        (九)CloseClipboard关闭剪贴板- Declare Function CloseClipboard Lib "user32"() As Long
  成功,返回一个非0值;失败返回0
        有了上述的套路,我们就可以随意的读取剪贴板的相应数据了。  | 
4楼 xmyjk | 
 简易剪贴板查看程序.zip
  查看程序码源:- Option Explicit
  
 - Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
  - Private Declare Function CloseClipboard Lib "user32" () As Long
  - Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
  - Private Declare Function EmptyClipboard Lib "user32" () As Long
  - Private Declare Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long
  - Private Declare Function GetClipboardFormatName Lib "user32" Alias "GetClipboardFormatNameA" (ByVal wFormat As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
  
 - Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  - Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  - Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
  - Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  
 - Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (PicDesc As uPicDesc, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
  - Private Declare Function CopyEnhMetaFile Lib "gdi32" Alias "CopyEnhMetaFileA" (ByVal hemfSrc As Long, ByVal lpszFile As String) As Long
  - Private Declare Function CopyImage Lib "user32" (ByVal handle As Long, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
  
 - Private Type GUID
  -     Data1 As Long
  -     Data2 As Integer
  -     Data3 As Integer
  -     Data4(0 To 7) As Byte
  - End Type
  - Private Type uPicDesc
  -     Size As Long
  - Type As Long
  -     hPic As Long
  -     hPal As Long
  - End Type
  
 - Private Sub CommandButton1_Click()
  -     ListBox1.Clear
  -     TextBox1.Value = ""
  -     Set Image1.Picture = Nothing
  -     TextBox1.Visible = True
  -     Image1.Visible = False
  -     listclpformate
  - End Sub
  
 - Private Sub ListBox1_Click()
  -     TextBox1.Visible = False
  -     Image1.Visible = False
  -     Dim hMem As Long, ClpData As Long, ClpSize As Long, byt() As Byte, clptext As String, fv As Long, hp As Long, f As Long
  -     If ListBox1.ListIndex <> 0 Then
  -         fv = ListBox1.List(ListBox1.ListIndex)
  -         OpenClipboard 0&
  -         Select Case fv
  -         Case 1, 7, 13
  -             hMem = GetClipboardData(1)
  -             If hMem <> 0 Then
  -                 ClpData = GlobalLock(hMem)
  -                 ClpSize = GlobalSize(hMem)
  -                 If ClpData <> 0 And ClpSize > 0 Then
  -                     ReDim byt(0 To ClpSize - 1) As Byte
  -                     CopyMemory byt(0), ByVal ClpData, ByVal ClpSize
  -                     clptext = StrConv(byt, vbUnicode)
  -                 End If
  -                 GlobalUnlock hMem
  -             End If
  -             TextBox1.Visible = True
  -             TextBox1.Text = clptext
  -         Case 2, 8, 3, 14
  -             Select Case fv
  -             Case 2, 8
  -                 f = 2
  -                 hMem = GetClipboardData(2)
  -                 hp = CopyImage(hMem, 0&, 0, 0, &H4)
  -             Case Else
  -                 f = 14
  -                 hMem = GetClipboardData(14)
  -                 hp = CopyEnhMetaFile(hMem, vbNullString)
  -             End Select
  -             If hMem <> 0 Then
  -                 Dim uPicInfo As uPicDesc, IID_IDispatch As GUID, IPic As IPictureDisp
  -                 With IID_IDispatch
  -                     .Data1 = &H7BF80980
  -                     .Data2 = &HBF32
  -                     .Data3 = &H101A
  -                     .Data4(0) = &H8B
  -                     .Data4(1) = &HBB
  -                     .Data4(2) = &H0
  -                     .Data4(3) = &HAA
  -                     .Data4(4) = &H0
  -                     .Data4(5) = &H30
  -                     .Data4(6) = &HC
  -                     .Data4(7) = &HAB
  -                 End With
  -                 With uPicInfo
  -                     .Size = Len(uPicInfo)
  -                     .Type = IIf(f = 2, 1, 4)
  -                     .hPic = hp
  -                 End With
  -                 OleCreatePictureIndirect uPicInfo, IID_IDispatch, True, IPic
  -                 Image1.Visible = True
  -                 Set Image1.Picture = IPic
  -             End If
  -         Case Else
  -             hMem = GetClipboardData(fv)
  -             If hMem <> 0 Then
  -                 ClpData = GlobalLock(hMem)
  -                 ClpSize = GlobalSize(hMem)
  -                 If ClpData <> 0 And ClpSize > 0 Then
  -                     ReDim byt(0 To ClpSize - 1) As Byte
  -                     CopyMemory byt(0), ByVal ClpData, ByVal ClpSize
  -                     clptext = BinArrayToHex(byt)
  -                 End If
  -                 GlobalUnlock hMem
  -             End If
  -             clptext = clptext & vbCrLf & vbCrLf & "识别可能文本:" & vbCrLf & StrConv(byt, vbUnicode)
  -             TextBox1.Visible = True
  -             TextBox1.Text = clptext
  -         End Select
  -         CloseClipboard
  -     End If
  - End Sub
  
 - Sub listclpformate()
  -     Dim fname As String, f As Long, d
  -     Set d = CreateObject("scripting.dictionary")
  -     OpenClipboard 0&
  -     f = EnumClipboardFormats(0)
  -     Do While f <> 0
  -         Select Case f
  -         Case 1
  -             fname = "文本"
  -         Case 2
  -             fname = "位图"
  -         Case 3
  -             fname = "MetaFilePict图片"
  -         Case 4
  -             fname = "SYLK"
  -         Case 5
  -             fname = "Dif"
  -         Case 6
  -             fname = "Tiff"
  -         Case 7
  -             fname = "OEM文本"
  -         Case 8
  -             fname = "DIB位图"
  -         Case 9
  -             fname = "Pallette"
  -         Case 10
  -             fname = "PenData"
  -         Case 11
  -             fname = "Riff"
  -         Case 12
  -             fname = "Wave"
  -         Case 13
  -             fname = "Unicode文字"
  -         Case 14
  -             fname = "增强型图元文件"
  -         Case 15
  -             fname = "HDrop"
  -         Case 16
  -             fname = "区域设置"
  -         Case 17
  -             fname = "DIBV5位图"
  -         Case 18
  -             fname = "Max"
  -         Case 128
  -             fname = "CF_OWNERDISPLAY"
  -         Case 129
  -             fname = "显示文本"
  -         Case 130
  -             fname = "CF_DSPBITMAP"
  -         Case 131
  -             fname = "CF_DSPMETAFILEPICT"
  -         Case 142
  -             fname = "CF_DSPENHMETAFILE"
  -         Case 512
  -             fname = "CF_PRIVATEFIRST"
  -         Case 767
  -             fname = "CF_PRIVATELAST"
  -         Case 768
  -             fname = "CF_GDIOBJFIRST"
  -         Case 1023
  -             fname = "CF_GDIOBJLAST"
  -         Case Else:
  -             fname = Space(255)
  -             GetClipboardFormatName f, fname, 255
  -             fname = Trim(fname)
  -             If fname <> "" Then
  -                 fname = Left(fname, Len(fname) - 1)
  -             End If
  -         End Select
  -         d(fname) = f
  -         f = EnumClipboardFormats(f)
  -     Loop
  -     CloseClipboard
  -     If d.Count > 0 Then
  -         Dim arr(), i&, k, it
  -         ReDim arr(0 To d.Count, 0 To 1)
  -         k = d.keys
  -         it = d.items
  -         arr(0, 0) = "格式编码"
  -         arr(0, 1) = "格式名称"
  -         For i = 1 To d.Count
  -             arr(i, 0) = it(i - 1)
  -             arr(i, 1) = k(i - 1)
  -         Next
  -         ListBox1.List = arr
  -     End If
  - End Sub
  
 - Private Sub UserForm_Initialize()
  -     TextBox1.Visible = True
  -     Image1.Visible = False
  -     listclpformate
  - End Sub
  
 - Private Function BinArrayToHex(Bin() As Byte) As String
  -     Dim iLoop As Long
  -     Dim sResult As String
  -     Dim m&
  -     m = 1
  -     sResult = Space((UBound(Bin) - LBound(Bin) + 1) * 4)
  -     For iLoop = LBound(Bin) To UBound(Bin)
  -         Mid(sResult, (iLoop - LBound(Bin)) * 4 + 1, 2) = Right("0" & Hex(Bin(iLoop)), 2)
  -         If m = 16 Then Mid(sResult, (iLoop - LBound(Bin)) * 4 + 3, 2) = vbCrLf: m = 0
  -         m = m + 1
  -     Next iLoop
  -     BinArrayToHex = Trim(sResult)
  - End Function
     | 
5楼 xmyjk | 
四、如何监控剪贴板
  (较难,作为拓展补充,以下涉及的知识,需要有WINDOWS消息传递机制和拦截WINDOWS消息的基础知识(或者再另贴讲吧)。涉及到相关的API,就不详细阐述,读者可自行查阅API手册。)
        WINDOWS剪贴板观察器(Clipboard Viewer)是一个显示剪贴板当前内容的窗口。剪贴板观察链(Clipboard Viewer Chain)是一系列相互独立的剪贴板观察窗口,是保存Clipboard   Viewer窗口以及他们之间的前后向关系的一个Windows系统链表,它们都能够监控并读取当前发送到剪贴板的内容。
        如何将我们的程序,注册成一个系统认可并可实时刷新的剪贴板监视程序呢?       首先,使用SetClipboardViewer函数向剪贴板观察链中加入一个观察窗口。该函数需要传递的参数是观察窗口的句柄。返回值也是链条下一个窗口句柄。当一个窗口注册为Clipboard Viewer后,他会被加入Clipboard Viewer Chain,并得到链表中下一个Viewer窗口的句柄,该句柄必须保存以在响应消息时使用。Windows正是通过Clipboard Viewer Chain保证了所有Clipboard Viewer能接收和响应剪贴板变化消息。当剪贴板的内容发生变化时,该窗口会接收到一个WM_DRAWCLIPBOARD的消息。       然后,响应WM_DRAWCLIPBOARD消息处理剪贴板内容的变化。       最后,在程序退出或关闭时需要调用ChangeClipboardChain函数来将自己从观察链中删除。然后调用SendMessage函数把这些消息传递到观察链中的下一个观察窗口。
        另外,窗口都是有自己的窗口程序,来相应WINDOWS之间的消息传递,我们要把我们的窗体程序,注册成为相应剪贴板消息的监视程序,还需要如下步骤:       首先,先用一个句柄,用GetWindowLong函数记录原来的窗口程序;       然后,用SetWindowLong函数,设置相应剪贴板消息的监视程序和窗口进行绑定;       接着,循环处理WINDOWS系统发来的消息,如果是剪贴板相关的消息,就来用我们写的剪贴板查看程序来处理,如果是非剪贴板查看的其他消息,就用CallWindowProc函数调用窗口原来的窗口程序处理消息。       最后,当结束时,再次使用SetWindowLong将原窗口程序还原。              不过,我做出来的程序,在WINDOWS XP的系统环境下,会造成EXCEL崩溃,但是在WIN7环境下,程序没有任何问题。或许我的理解在某方面还是有偏差的吧。待查证补充。也请大家指点。   | 
6楼 xmyjk | 
 简易剪贴板监视查看程序.zip
  剪贴板监视工具,标准模块代码:- Option Explicit
  - Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  - Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  - Private Const WM_DRAWCLIPBOARD = &H308
  - Private Const WM_CHANGECBCHAIN = &H30D
  - Public PrevProc As Long
  - Public hwnd As Long
  - Public hwndNextViewer As Long
  
 - Sub lo()
  -     UserForm1.Show 0
  - End Sub
  
 - Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  -     Select Case uMsg
  -     Case WM_CHANGECBCHAIN
  -         If wParam = hwndNextViewer Then
  -             hwndNextViewer = lParam
  -         ElseIf hwndNextViewer <> 0 Then
  -             SendMessage hwndNextViewer, uMsg, wParam, lParam
  -         End If
  -     Case WM_DRAWCLIPBOARD
  -         UserForm1.ListBox1.Clear
  -         UserForm1.TextBox1.Value = ""
  -         Set UserForm1.Image1.Picture = Nothing
  -         UserForm1.TextBox1.Visible = True
  -         UserForm1.Image1.Visible = False
  -         UserForm1.listclpformate
  -         SendMessage hwndNextViewer, uMsg, wParam, lParam
  -     End Select
  -     WindowProc = CallWindowProc(PrevProc, hwnd, uMsg, wParam, lParam)
  
 - End Function
  
  窗体代码:- Option Explicit
  
 - Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
  - Private Declare Function CloseClipboard Lib "user32" () As Long
  - Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
  - Private Declare Function EmptyClipboard Lib "user32" () As Long
  - Private Declare Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long
  - Private Declare Function GetClipboardFormatName Lib "user32" Alias "GetClipboardFormatNameA" (ByVal wFormat As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
  
 - Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  - Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  - Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
  - Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  
 - Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (PicDesc As uPicDesc, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
  - Private Declare Function CopyEnhMetaFile Lib "gdi32" Alias "CopyEnhMetaFileA" (ByVal hemfSrc As Long, ByVal lpszFile As String) As Long
  - Private Declare Function CopyImage Lib "user32" (ByVal handle As Long, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
  
 - Private Type GUID
  -     Data1 As Long
  -     Data2 As Integer
  -     Data3 As Integer
  -     Data4(0 To 7) As Byte
  - End Type
  - Private Type uPicDesc
  -     Size As Long
  - Type As Long
  -     hPic As Long
  -     hPal As Long
  - End Type
  
 - Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  - Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
  - Private Declare Function SetClipboardViewer Lib "user32" (ByVal hwnd As Long) As Long
  - Private Declare Function ChangeClipboardChain Lib "user32" (ByVal hwnd As Long, ByVal hWndNext As Long) As Long
  
 - Const GWL_WNDPROC = (-4)
  
 - Private Sub ListBox1_Click()
  -     TextBox1.Visible = False
  -     Image1.Visible = False
  -     Dim hMem As Long, ClpData As Long, ClpSize As Long, byt() As Byte, clptext As String, fv As Long, hp As Long, f As Long
  -     If ListBox1.ListIndex <> 0 Then
  -         fv = ListBox1.List(ListBox1.ListIndex)
  -         OpenClipboard 0&
  -         Select Case fv
  -         Case 1, 7, 13
  -             hMem = GetClipboardData(1)
  -             If hMem <> 0 Then
  -                 ClpData = GlobalLock(hMem)
  -                 ClpSize = GlobalSize(hMem)
  -                 If ClpData <> 0 And ClpSize > 0 Then
  -                     ReDim byt(0 To ClpSize - 1) As Byte
  -                     CopyMemory byt(0), ByVal ClpData, ByVal ClpSize
  -                     clptext = StrConv(byt, vbUnicode)
  -                 End If
  -                 GlobalUnlock hMem
  -             End If
  -             TextBox1.Visible = True
  -             TextBox1.Text = clptext
  -         Case 2, 8, 3, 14
  -             Select Case fv
  -             Case 2, 8
  -                 f = 2
  -                 hMem = GetClipboardData(2)
  -                 hp = CopyImage(hMem, 0&, 0, 0, &H4)
  -             Case Else
  -                 f = 14
  -                 hMem = GetClipboardData(14)
  -                 hp = CopyEnhMetaFile(hMem, vbNullString)
  -             End Select
  -             If hMem <> 0 Then
  -                 Dim uPicInfo As uPicDesc, IID_IDispatch As GUID, IPic As IPictureDisp
  -                 With IID_IDispatch
  -                     .Data1 = &H7BF80980
  -                     .Data2 = &HBF32
  -                     .Data3 = &H101A
  -                     .Data4(0) = &H8B
  -                     .Data4(1) = &HBB
  -                     .Data4(2) = &H0
  -                     .Data4(3) = &HAA
  -                     .Data4(4) = &H0
  -                     .Data4(5) = &H30
  -                     .Data4(6) = &HC
  -                     .Data4(7) = &HAB
  -                 End With
  -                 With uPicInfo
  -                     .Size = Len(uPicInfo)
  -                     .Type = IIf(f = 2, 1, 4)
  -                     .hPic = hp
  -                 End With
  -                 OleCreatePictureIndirect uPicInfo, IID_IDispatch, True, IPic
  -                 Image1.Visible = True
  -                 Set Image1.Picture = IPic
  -             End If
  -         Case Else
  -             hMem = GetClipboardData(fv)
  -             If hMem <> 0 Then
  -                 ClpData = GlobalLock(hMem)
  -                 ClpSize = GlobalSize(hMem)
  -                 If ClpData <> 0 And ClpSize > 0 Then
  -                     ReDim byt(0 To ClpSize - 1) As Byte
  -                     CopyMemory byt(0), ByVal ClpData, ByVal ClpSize
  -                     clptext = BinArrayToHex(byt)
  -                 End If
  -                 GlobalUnlock hMem
  -             End If
  -             TextBox1.Visible = True
  -             TextBox1.Text = clptext
  -         End Select
  -         CloseClipboard
  -     End If
  - End Sub
  
 - Sub listclpformate()
  -     Dim fname As String, f As Long, d
  -     Set d = CreateObject("scripting.dictionary")
  -     OpenClipboard 0&
  -     f = EnumClipboardFormats(0)
  -     Do While f <> 0
  -         Select Case f
  -         Case 1
  -             fname = "文本"
  -         Case 2
  -             fname = "位图"
  -         Case 3
  -             fname = "MetaFilePict图片"
  -         Case 4
  -             fname = "SYLK"
  -         Case 5
  -             fname = "Dif"
  -         Case 6
  -             fname = "Tiff"
  -         Case 7
  -             fname = "OEM文本"
  -         Case 8
  -             fname = "DIB位图"
  -         Case 9
  -             fname = "Pallette"
  -         Case 10
  -             fname = "PenData"
  -         Case 11
  -             fname = "Riff"
  -         Case 12
  -             fname = "Wave"
  -         Case 13
  -             fname = "Unicode文字"
  -         Case 14
  -             fname = "增强型图元文件"
  -         Case 15
  -             fname = "HDrop"
  -         Case 16
  -             fname = "区域设置"
  -         Case 17
  -             fname = "DIBV5位图"
  -         Case 129
  -             fname = "显示文本"
  -         Case Else:
  -             fname = Space(255)
  -             GetClipboardFormatName f, fname, 255
  -             fname = Trim(fname)
  -             If fname <> "" Then
  -                 fname = Left(fname, Len(fname) - 1)
  -             End If
  -         End Select
  -         d(fname) = f
  -         f = EnumClipboardFormats(f)
  -     Loop
  -     CloseClipboard
  -     If d.Count > 0 Then
  -         Dim arr(), i&, k, it
  -         ReDim arr(0 To d.Count, 0 To 1)
  -         k = d.keys
  -         it = d.items
  -         arr(0, 0) = "格式编码"
  -         arr(0, 1) = "格式名称"
  -         For i = 1 To d.Count
  -             arr(i, 0) = it(i - 1)
  -             arr(i, 1) = k(i - 1)
  -         Next
  -         ListBox1.List = arr
  -     End If
  - End Sub
  
 - Sub UserForm_Initialize()
  -     TextBox1.Visible = True
  -     Image1.Visible = False
  -     listclpformate
  -     hwnd = FindWindow(vbNullString, Me.Caption)
  -     hwndNextViewer = SetClipboardViewer(hwnd)
  -     PrevProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)
  
 - End Sub
  
 - Private Function BinArrayToHex(Bin() As Byte) As String
  -     Dim iLoop As Long
  -     Dim sResult As String
  -     Dim m&
  -     m = 1
  -     sResult = Space((UBound(Bin) - LBound(Bin) + 1) * 4)
  -     For iLoop = LBound(Bin) To UBound(Bin)
  -         Mid(sResult, (iLoop - LBound(Bin)) * 4 + 1, 2) = Right("0" & Hex(Bin(iLoop)), 2)
  -         If m = 16 Then Mid(sResult, (iLoop - LBound(Bin)) * 4 + 3, 2) = vbCrLf: m = 0
  -         m = m + 1
  -     Next iLoop
  -     BinArrayToHex = Trim(sResult)
  - End Function
  
 - Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
  -     ChangeClipboardChain hwnd, hwndNextViewer
  -     SetWindowLong hwnd, GWL_WNDPROC, PrevProc
  - End Sub
     | 
7楼 xmyjk | 
五、其他补遗
  (一)剪贴板数据格式注册函数 Declare Function RegisterClipboardFormat Lib "user32" Alias "RegisterClipboardFormatA" (ByVal lpString As String) As Long 参数lpString表示指定要注册的剪贴板格式的名称 注册成功,则返回该剪贴板格式所对应的编号,失败,则返回0;        如果被注册的剪贴板格式名称已经存在,并不会重新注册一个新的剪贴板格式,而是返回原有的同名剪贴板格式编号。
  (二)获取剪贴板数据格式名称的API函数 Declare Function GetClipboardFormatName Lib "user32" Alias "GetClipboardFormatNameA" (ByVal wFormat As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long 参数:wFormat表示剪贴板格式的编码;lpString表示用于接收剪贴板格式名称的缓冲字符串;nMaxCount:缓冲字符串的字节长度,超出部分将被截去。 成功, 返回lpString中储存相关格式名称的字节数,否则返回0
  (三)将数据上传剪贴板的API函数 Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long 参数:wFormat表示剪贴板格式的编码;hMem表示上传的数据对象的句柄
  (四)其他功能函数 CountClipboardFormats:返回剪贴板可用数据格式的个数 EmptyClipboard:清空剪贴板 GetClipboardOwner:获取当前剪贴板是属于哪一个窗口的句柄 GetClipboardSequenceNumber:返回剪贴板序号 GetClipboardViewer:返回剪贴板监控程序所属窗口的句柄 GetOpenClipboardWindow:返回打开剪贴板的那个窗口句柄
  (五) 另外,如果是纯文本格式数据对剪贴板的访问,可以使用DATAOBJECT,可参阅我以前写过的一个帖子。 如何运用VBA实现复制指定选择的单元格区域的数据,使粘贴到QQ后出现的是文本形式的 http://www.exceltip.net/thread-26337-1-1.html
    | 
8楼 bishunbiao | 
只能仰视啦,收藏下  | 
9楼 herelazy | 
太牛啦**!仰望中!  | 
10楼 千年一梦遥 | 
太牛啦**!仰望中!  | 
11楼 xyf2210 | 
太牛啦**!仰望中!  | 
12楼 CheryBTL | 
哇~~~师傅太牛了**** 
  
  
    | 
13楼 YESS95 | 
烧香,膜拜,……  | 
14楼 水星钓鱼 | 
仰望,膜拜,精华  | 
15楼 yjzstar | 
仰望加收藏
    | 
16楼 白米饭 | 
仰望中,有点晕  | 
17楼 冬冬WarmUp | 
太牛啦**!仰望中!  | 
18楼 dhf327 | 
好东西,学习学习  |