剪贴板监视问题

oicqpen 2005-05-16 11:24:39
有个朋友很喜欢玩《帝国时代》,但他技术很差,打不过时就用秘籍造“眼镜蛇车”:按回车后输入“how to you turn this on”。为了方便造车,他把这几个单词“复制”后反复粘贴,一次造一大堆车。^_^
  于是,我赶制了一个小程序,当他复制了那个句子后,我的程序立刻打开剪贴板,把剪贴板中的内容改为“11 不许造车!那是作弊,明白吗!”,看着他造车时的一脸茫然,滇狐窃笑。
  即使不玩《帝国时代》,这样的剪贴板恶作剧也是很好玩的,和我一起做这个有趣的工程吧!
  首先,打开“记事本”,写一个“文字替换表”:
cheese steak jimmy's
11 农业是立国之本,好好种田!
lumberjack
11 砍柴,砍柴,快砍柴!!
rock on
11 大石头滚下来啦!哈哈哈!
robin hood
11 罗宾汉说他暂时没有钱。
how do you turn this on
11 不许造车!那是作弊,明白吗!
to smithereens
11 本·拉登的手下都去办事了,没空帮你破坏。
i love the monkey head
11 都什么年代了,你还相信“草上飞”?

  写完以后,把文件保存到你的VB工程路径下,命名为“BadClip.txt”。我只是举个例子,你完全可以根据你自己的需要写你的文字替换表。
  然后,打开VB,新建一个工程,并添加一个模块,写入以下API声明:
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) 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
Public 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 SetClipboardViewer Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function ChangeClipboardChain Lib "user32" (ByVal hwnd As Long, ByVal hWndNext As Long) As Long
Public Declare Function GetCurrentProcessId Lib "kernel32" () As Long

Public Declare Function RegisterServiceProcess Lib "kernel32" (ByVal ProcessID As Long, ByVal nFlag As Integer) As Long

Public Const GWL_WNDPROC = (-4)
Public Const WM_DRAWCLIPBOARD = &H308
Public Const WM_CHANGECBCHAIN = &H30D
  注意:RegisterServiceProcess是一个前几期用过的Api,VB的API查看器中没有这个函数,请到这儿“复制粘贴”。
  然后就可以写程序了,先在模块中写入以下代码:
Public hNext As Long
Public lpPrevWndProc As Long

Public Type Table
sFrom As String
sTo As String
End Type

'剪贴板数据替换表
Public aList(1000) As Table
Public TableCount As Integer

'修改剪贴板数据
Public Sub ChangeClip()
For i% = 0 To TableCount
If LCase$(Clipboard.GetText()) = aList(i%).sFrom Then
Clipboard.SetText aList(i%).sTo
End If
Next i%
End Sub

'窗体过程
Public Function WndProc(ByVal hwnd As Long, ByVal uMessage As Long, ByVal wparam As Long, ByVal lparam As Long) As Long
Select Case uMessage
'剪贴板数据被改动
Case WM_DRAWCLIPBOARD
SendMessage hNext, WM_DRAWCLIPBOARD, 0, 0
ChangeClip
WndProc = 0
'剪贴板链被改动
Case WM_CHANGECBCHAIN
If hNext = wparam Then
hNext = lparam
End If
WndProc = 0
'其它情况调用原有窗体过程
Case Else
WndProc = CallWindowProc(lpPrevWndProc, hwnd, uMessage, wparam, lparam)
End Select
End Function

Public Sub hook(hwnd As Long)
'子类化窗体
lpPrevWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WndProc)
'设置剪贴板监视
hNext = SetClipboardViewer(hwnd)
End Sub

Public Sub unhook(hwnd As Long)
'解除窗体子类化
SetWindowLong hwnd, GWL_WNDPROC, lpPrevWndProc
'解除对剪贴板的监视
ChangeClipboardChain hwnd, hNext
End Sub

  然后,双击窗体,为窗体写入以下代码:
Private Sub Form_Load()
'将程序从“关闭程序”列表中去掉
RegisterServiceProcess GetCurrentProcessId, 1
'隐藏窗体
Me.Hide

'读取“文字替换表”
Open App.Path & "\BadClip.txt" For Input As 1

While Not EOF(1)
Line Input #1, aList(TableCount).sFrom
If Not EOF(1) Then
Line Input #1, aList(TableCount).sTo

aList(TableCount).sFrom = Trim$(LCase$(aList(TableCount).sFrom))
aList(TableCount).sTo = Trim$(LCase$(aList(TableCount).sTo))

TableCount = TableCount + 1
End If
Wend

Close #1
'设置子类化和剪贴板监视
hook Me.hwnd
End Sub

'为了调试而写的,实际使用中这个函数的不到执行
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
unhook Me.hwnd
End Sub

以上代码可能在98才有用,但到了WIN 2000 SERVER 版本就不可以实现,那位朋友可以提供剪贴板监视原代码给小弟,谢谢
...全文
339 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
DooDu 2005-05-17
  • 打赏
  • 举报
回复
Option Explicit
Dim cc As String
Dim pFlag As Boolean
Private Sub Command1_Click()
Timer1.Interval = 200
Timer1.Enabled = Not Timer1.Enabled
End Sub

Private Sub Timer1_Timer()
cc = Clipboard.GetText
Select Case cc
Case "cheese steak jimmy's"
MsgBox "农业是立国之本,好好种田"
Clipboard.Clear
Case "lumberjack"
MsgBox "砍柴,砍柴,快砍柴!!"
Clipboard.Clear
End Select
DoEvents
End Sub

这个是轮讯的苯方法~~不过要api监视是要钩子的吧?很麻烦
还想懒够 2005-05-17
  • 打赏
  • 举报
回复
http://www.vbaccelerator.com/home/VB/Code/Libraries/Clipboard/index.asp

可以参考一下。里面有类似的的监控的代码,需要改动一下。
DooDu 2005-05-17
  • 打赏
  • 举报
回复
http://www.vbaccelerator.com/home/VB/Code/Libraries/Clipboard/Customising_Clipboard_Use/VB6_Clipoard_Classes_and_Sample.zip


=======================



c的:


实现网络蚂蚁的实时监视剪贴板功能
作者:黑龙江省五大连池 马明臣
我们知道,网络蚂蚁能够实时地监视剪贴板,如果我们能够在自己的程序中实现这个功能,肯定为我们的程序增色不少。
那它到底是如何实现的呢?我们可以想到的最简单的方法是,直接开个计时器,定时检查剪贴板上的内容,或者另写个线程来检查。这两个方法都能够监视剪贴板,但遗憾的是实时性太差,又占用了系统的大量资源,很不合算。好一点的方法可以用Win32API中关于剪贴板钩子(HOOK)的函数,只要安装了剪贴板的钩子函数,就可以做到实时地监视剪贴板,因为任何剪贴板的改变都会触发一条消息,而钩子函数拦截了这条信息。然而,这要求当前程序必须要有机会获得CPU控制权才能处理这个消息。如果该程序这时并没有释放CPU,监视剪贴板的程序并不能处理消息。只有当该程序执行完了之后,别的程序才能获得处理机会,但此时,剪贴板只剩下最后一次粘贴的内容了。而且,使用钩子函数非常危险,一旦你的程序出了问题,整个系统也就跟着瘫痪了。
既然这些方法都不太理想,那我们不妨转换一下思维,不再去管剪贴板,而想想如何让剪贴板直接向自己的程序发消息,这样肯定能做到百分之百的实时。为此我仔细的查看了各种Windows的编程资料,结果是:因为剪贴板不具有自己的句柄(Handle),它本身也不是Windows的一个类,故剪贴板是不会自己发消息的。但是系统是如何能够接收剪切/拷贝到剪贴板等命令呢?也即是如何接收WM_COPY和WM_CUT,WM_PASTE等消息呢?经过研究发现能够发送消息的是剪贴板查看器,原来多个剪贴板查看器依次连接成剪贴板查看链。因此,要实现实时监视剪贴板必须将自己的程序注册成为剪贴板查看器(即加入链表中)。下面笔者以C++ Builder 5.0为例编程说明其具体实现过程。
首先新建一个工程,在Form1上增加一个Memo控件,然后在Form1的.h里面加上#include <vcl\Clipbrd.hpp>,因为下面要用到的API函数大多是在该头文件中定义的。
在Form1的.h的public加上:
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_DRAWCLIPBOARD,TMessage,ClipboardChanged) //映射这个消息
END_MESSAGE_MAP(TForm)
HWND LastHandle;// 用于保存剪贴板查看器链中下一个窗口的句柄。
接下来,当然是把自己的程序窗口注册成为剪贴板查看器了。在Form1的OnCreate事件中加入一句:
LastHandle=SetClipboardViewer(Form1->Handle);
该函数会将指定的窗口加入剪贴板查看器链,参数handle就是你欲新加入的窗口的句柄,返回值则为系统的剪贴板查看器链中下一个窗口的句柄。
当你自己的程序退出时,必须从剪贴板查看器链中删除本窗口。在Form1的OnClose事件中加入两句:
ChangeClipboardChain(Form1->Handle,LastHandle);
函数ChangeClipboardChain是SetClipboardViewer的逆操作,能将第一个参数handle指定的窗口从剪贴板查看器链中删除,第二个参数是剪贴板查看器链中下一个窗口的句柄,是供系统调整剪贴板查看器链表用的,我们不用管它。
最后一步,也是最关键的一步,如果剪贴板内容有变化,窗口将自动激活 WM_DRAWCLIPBOARD消息,也即间接地实现了让剪贴板向自己的程序发消息的功能,这就能够实时监视剪贴板,相信网络蚂蚁也应该是用这个方法。有一点要注意的是,在接收处理WM_DRAWCLIPBOARD消息时要将消息传递给剪贴板查看链中的下一个窗口,以便让其它程序也能监视剪贴板,因为该消息只直接发给链中的第一个程序,其他程序不会直接收到该消息。
程序如下,在Form1的.h的private加上:
void __fastcall ClipboardChanged(TMessage& Msg);
再编写自己的处理过程,这就是你自由发挥的地方了。本例设为自动将剪贴板的文本粘贴到Memo控件中。
在Form1的.cpp内加上:
void __fastcall TForm1::ClipboardChanged(TMessage& Msg)
{
 if (Clipboard()->HasFormat(CF_TEXT))
Memo1->Text = Clipboard()->AsText;
}
这一过程中使用了 TClipboard 类的 Clipboard 函数获取剪贴板内文本内容,至于如何获取剪贴板内的其它非文本类型的内容则不在本文讨论范围内了,读者可自己在C++ Builder中输入TClipboard ,再按F1,键,就可以看到各个函数的详细用法了,不过这些帮助可都是英文的呀!
以上程序在C++ Builder 5.0+PWIN98系统下调试通过,由于笔者水平有限,上文如有不妥之处,请大家与我一起探讨。


http://cache.baidu.com/c?word=%CA%B5%CA%B1%3B%BC%E0%CA%D3%3B%BC%F4%CC%F9%3B%B0%E5&url=http%3A//www%2Edelphijs%2Ecom/Article%5FPrint%2Easp%3FArticleID%3D1320&b=0&a=29&user=baidu

delphi的
oicqpen 2005-05-17
  • 打赏
  • 举报
回复
这个是轮讯的苯方法~~不过要api监视是要钩子的吧?很麻烦

钩子要怎么样理解呢
oicqpen 2005-05-17
  • 打赏
  • 举报
回复
jjkk168(老加班的人--每日要顶二十贴)

找不到啦 ,你是否可以帮我找一下

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧