vb高手进,关于自动点击按钮的问题
编了一个网页快照的程序,关键代码如下:PrivateSubCommand1_Click()DimlnghwdAsLonglnghwd=FindWindowEx(Me.hw...
编了一个网页快照的程序,关键代码如下:
Private Sub Command1_Click()
Dim lnghwd As Long
lnghwd = FindWindowEx(Me.hwnd, 0, "Shell Embedding", vbNullString)
lnghwd = FindWindowEx(lnghwd, 0, "Shell DocObject View", vbNullString)
SendMessage lnghwd, WM_PRINT, Picture1.hdc, PRF_CHILDREN Or PRF_CLIENT Or PRF_ERASEBKGND Or PRF_NONCLIENT Or PRF_OWNED
Picture1.Refresh
End Sub
其中Picture1的AutoRedraw 属性为True.
在Private Sub WebBrowser1_DownloadComplete()事件中模拟点击Command1按钮:
Call Command1_Click
结果Picture1中无法显示Webbrowser1中的图像,而手动点击Command1 却可以实现,哪位高手能告诉我为什么?
答出有加分!!谢谢。
不好意思,我已经用SendMessage成功的实现了我想要的效果和功能,我只想知道为什么vb会有这样的特性?
难道Call Command**_Click 不等于手动点击?为什么呢? 展开
Private Sub Command1_Click()
Dim lnghwd As Long
lnghwd = FindWindowEx(Me.hwnd, 0, "Shell Embedding", vbNullString)
lnghwd = FindWindowEx(lnghwd, 0, "Shell DocObject View", vbNullString)
SendMessage lnghwd, WM_PRINT, Picture1.hdc, PRF_CHILDREN Or PRF_CLIENT Or PRF_ERASEBKGND Or PRF_NONCLIENT Or PRF_OWNED
Picture1.Refresh
End Sub
其中Picture1的AutoRedraw 属性为True.
在Private Sub WebBrowser1_DownloadComplete()事件中模拟点击Command1按钮:
Call Command1_Click
结果Picture1中无法显示Webbrowser1中的图像,而手动点击Command1 却可以实现,哪位高手能告诉我为什么?
答出有加分!!谢谢。
不好意思,我已经用SendMessage成功的实现了我想要的效果和功能,我只想知道为什么vb会有这样的特性?
难道Call Command**_Click 不等于手动点击?为什么呢? 展开
3个回答
展开全部
1.局部级模拟
键盘事件是最终被送到活动窗口,然后才引起目标程序响应的。那么最直接的模拟方法就是:直接伪造一个键盘消息发给目标程序。哈哈,这实在是很简单,windows提供了几个这样的API函数可以实现直接向目标程序发送消息的功能,常用的有SendMessage和PostMessage,它们的区别是PostMessage函数直接把消息仍给目标程序就不管了,而SendMessage把消息发出去后,还要等待目标程序返回些什么东西才好。这里要注意的是,模拟键盘消息一定要用PostMessage函数才好,用SendMessage是不正确的(因为模拟键盘消息是不需要返回值的,不然目标程序会没反应),切记切记.
2.全局级模拟
你会发现,用上面的方法模拟按键并不是对所有程序都有效的,有的程序啊,你向它发了一大堆消息,可是它却一点反应也没有。这是怎么回事呢?这就要看具体的情况了,有些程序(特别是一些游戏)出于某些原因,会禁止用户对它使用模拟按键程序,这个怎么实现呢?比如可以在程序中检查一下,如果发现自己不是活动窗口,就不接受键盘消息。或者仔细检查一下收到的键盘消息,你会发现真实的按键和模拟的按键消息总是有一些小差别,从这些小差别上,目标程序就能判断出:这是假的!是伪造的!!因此,如果用PostMessage发送局部消息模拟按键不成功的话,你可以试一试全局级的键盘消息,看看能不能骗过目标程序。
模拟全局键盘消息常见的可以有以下一些方法:
(1) 用API函数keybd_event,这个函数可以用来模拟一个键盘事件,它的VB声明为:
Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
参数bVk表示要模拟的按键的虚拟码,bScan表示该按键的扫描码(一般可以传0),dwFlags表示是按下键还是释放键(按下键为0,释放键为2),dwExtraInfo是扩展标志,一般没有用。比如要模拟按下A键,可以这样:
Const KEYEVENTF_KEYUP = &H2
keybd_event VK_A, 0, 0, 0 '按下A键
keybd_event VK_A, 0, KEYEVENTF_KEYUP, 0 '释放A键
注意有时候按键的速度不要太快,否则会出问题,可以用API函数Sleep来进行延时,声明如下:
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
参数dwMilliseconds表示延时的时间,以毫秒为单位。
那么如果要模拟按下功能键怎么做呢?比如要按下Ctrl+C实现拷贝这个功能,可以这样:
keybd_event VK_Ctrl, 0, 0, 0 '按下Ctrl键
keybd_event VK_C, 0, 0, 0 '按下C键
Sleep 500 '延时500毫秒
keybd_event VK_C, 0, KEYEVENTF_KEYUP, 0 '释放C键
keybd_event VK_Ctrl, 0, KEYEVENTF_KEYUP, 0 '释放Ctrl键
好了,现在你可以试试是不是可以骗过目标程序了,这个函数对大部分的窗口程序都有效,可是仍然有一部分游戏对它产生的键盘事件熟视无睹,这时候,你就要用上bScan这个参数了。一般的,bScan都传0,但是如果目标程序是一些DirectX游戏,那么你就需要正确使用这个参数传入扫描码,用了它可以产生正确的硬件事件消息,以被游戏识别。这样的话,就可以写成这样:
keybd_event VK_A, MapVirtualKey(VK_A, 0), 0, 0 '按下A键
keybd_event VK_A, MapVirtualKey(VK_A, 0), KEYEVENTF_KEYUP, 0 '释放A键
以上就是用keybd_event函数来模拟键盘事件。除了这个函数,SendInput函数也可以模拟全局键盘事件。SendInput可以直接把一条消息插入到消息队列中,算是比较底层的了。它的VB声明如下:
Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As GENERALINPUT, ByVal cbSize As Long) As Long
参数:
nlnprts:定义plnputs指向的结构的数目。
plnputs:指向INPUT结构数组的指针。每个结构代表插人到键盘或鼠标输入流中的一个事件。
cbSize:定义INPUT结构的大小。若cbSize不是INPUT结构的大小,则函数调用失败。
返回值:函数返回被成功地插人键盘或鼠标输入流中的事件的数目。若要获得更多的错误信息,可以调用GetlastError函数。
备注:Sendlnput函数将INPUT结构中的事件顺序地插入键盘或鼠标的输入流中。这些事件与用户插入的(用鼠标或键盘)或调用keybd_event,mouse_event,或另外的Sendlnput插人的键盘或鼠标的输入流不兼容。
嗯,这个函数用起来蛮复杂的,因为它的参数都是指针一类的东西。要用它来模拟键盘输入,先要构造一组数据结构,把你要模拟的键盘消息装进去,然后传给它。为了方便起见,把它做在一个过程里面,要用的时候直接调用好了,代码如下:
Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As GENERALINPUT, ByVal cbSize As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Type GENERALINPUT
dwType As Long
xi(0 To 23) As Byte
End Type
Type KEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As Long
End Type
Const INPUT_KEYBOARD = 1
Sub MySendKey(bkey As Long)
'参数bkey传入要模拟按键的虚拟码即可模拟按下指定键
Dim GInput(0 To 1) As GENERALINPUT
Dim KInput As KEYBDINPUT
KInput.wVk = bkey '你要模拟的按键
KInput.dwFlags = 0 '按下键标志
GInput(0).dwType = INPUT_KEYBOARD
CopyMemory GInput(0).xi(0), KInput, Len(KInput) '这个函数用来把内存中KInput的数据复制到GInput
KInput.wVk = bkey
KInput.dwFlags = KEYEVENTF_KEYUP ' 释放按键
GInput(1).dwType = INPUT_KEYBOARD ' 表示该消息为键盘消息
CopyMemory GInput(1).xi(0), KInput, Len(KInput)
'以上工作把按下键和释放键共2条键盘消息加入到GInput数据结构中
SendInput 2, GInput(0), Len(GInput(0)) '把GInput中存放的消息插入到消息列队
End Sub
除了以上这些,用全局钩子也可以模拟键盘消息。如果你对windows中消息钩子的用法已经有所了解,那么你可以通过设置一个全局HOOK来模拟键盘消息,比如,你可以用WH_JOURNALPLAYBACK这个钩子来模拟按键。WH_JOURNALPLAYBACK是一个系统级的全局钩子,它和WH_JOURNALRECORD的功能是相对的,常用它们来记录并回放键盘鼠标操作。WH_JOURNALRECORD钩子用来将键盘鼠标的操作忠实地记录下来,记录下来的信息可以保存到文件中,而WH_JOURNALPLAYBACK则可以重现这些操作。当然亦可以单独使用WH_JOURNALPLAYBACK来模拟键盘操作。你需要首先声明SetWindowsHookEx函数,它可以用来安装消息钩子:
Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long,ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
键盘事件是最终被送到活动窗口,然后才引起目标程序响应的。那么最直接的模拟方法就是:直接伪造一个键盘消息发给目标程序。哈哈,这实在是很简单,windows提供了几个这样的API函数可以实现直接向目标程序发送消息的功能,常用的有SendMessage和PostMessage,它们的区别是PostMessage函数直接把消息仍给目标程序就不管了,而SendMessage把消息发出去后,还要等待目标程序返回些什么东西才好。这里要注意的是,模拟键盘消息一定要用PostMessage函数才好,用SendMessage是不正确的(因为模拟键盘消息是不需要返回值的,不然目标程序会没反应),切记切记.
2.全局级模拟
你会发现,用上面的方法模拟按键并不是对所有程序都有效的,有的程序啊,你向它发了一大堆消息,可是它却一点反应也没有。这是怎么回事呢?这就要看具体的情况了,有些程序(特别是一些游戏)出于某些原因,会禁止用户对它使用模拟按键程序,这个怎么实现呢?比如可以在程序中检查一下,如果发现自己不是活动窗口,就不接受键盘消息。或者仔细检查一下收到的键盘消息,你会发现真实的按键和模拟的按键消息总是有一些小差别,从这些小差别上,目标程序就能判断出:这是假的!是伪造的!!因此,如果用PostMessage发送局部消息模拟按键不成功的话,你可以试一试全局级的键盘消息,看看能不能骗过目标程序。
模拟全局键盘消息常见的可以有以下一些方法:
(1) 用API函数keybd_event,这个函数可以用来模拟一个键盘事件,它的VB声明为:
Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
参数bVk表示要模拟的按键的虚拟码,bScan表示该按键的扫描码(一般可以传0),dwFlags表示是按下键还是释放键(按下键为0,释放键为2),dwExtraInfo是扩展标志,一般没有用。比如要模拟按下A键,可以这样:
Const KEYEVENTF_KEYUP = &H2
keybd_event VK_A, 0, 0, 0 '按下A键
keybd_event VK_A, 0, KEYEVENTF_KEYUP, 0 '释放A键
注意有时候按键的速度不要太快,否则会出问题,可以用API函数Sleep来进行延时,声明如下:
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
参数dwMilliseconds表示延时的时间,以毫秒为单位。
那么如果要模拟按下功能键怎么做呢?比如要按下Ctrl+C实现拷贝这个功能,可以这样:
keybd_event VK_Ctrl, 0, 0, 0 '按下Ctrl键
keybd_event VK_C, 0, 0, 0 '按下C键
Sleep 500 '延时500毫秒
keybd_event VK_C, 0, KEYEVENTF_KEYUP, 0 '释放C键
keybd_event VK_Ctrl, 0, KEYEVENTF_KEYUP, 0 '释放Ctrl键
好了,现在你可以试试是不是可以骗过目标程序了,这个函数对大部分的窗口程序都有效,可是仍然有一部分游戏对它产生的键盘事件熟视无睹,这时候,你就要用上bScan这个参数了。一般的,bScan都传0,但是如果目标程序是一些DirectX游戏,那么你就需要正确使用这个参数传入扫描码,用了它可以产生正确的硬件事件消息,以被游戏识别。这样的话,就可以写成这样:
keybd_event VK_A, MapVirtualKey(VK_A, 0), 0, 0 '按下A键
keybd_event VK_A, MapVirtualKey(VK_A, 0), KEYEVENTF_KEYUP, 0 '释放A键
以上就是用keybd_event函数来模拟键盘事件。除了这个函数,SendInput函数也可以模拟全局键盘事件。SendInput可以直接把一条消息插入到消息队列中,算是比较底层的了。它的VB声明如下:
Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As GENERALINPUT, ByVal cbSize As Long) As Long
参数:
nlnprts:定义plnputs指向的结构的数目。
plnputs:指向INPUT结构数组的指针。每个结构代表插人到键盘或鼠标输入流中的一个事件。
cbSize:定义INPUT结构的大小。若cbSize不是INPUT结构的大小,则函数调用失败。
返回值:函数返回被成功地插人键盘或鼠标输入流中的事件的数目。若要获得更多的错误信息,可以调用GetlastError函数。
备注:Sendlnput函数将INPUT结构中的事件顺序地插入键盘或鼠标的输入流中。这些事件与用户插入的(用鼠标或键盘)或调用keybd_event,mouse_event,或另外的Sendlnput插人的键盘或鼠标的输入流不兼容。
嗯,这个函数用起来蛮复杂的,因为它的参数都是指针一类的东西。要用它来模拟键盘输入,先要构造一组数据结构,把你要模拟的键盘消息装进去,然后传给它。为了方便起见,把它做在一个过程里面,要用的时候直接调用好了,代码如下:
Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As GENERALINPUT, ByVal cbSize As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Type GENERALINPUT
dwType As Long
xi(0 To 23) As Byte
End Type
Type KEYBDINPUT
wVk As Integer
wScan As Integer
dwFlags As Long
time As Long
dwExtraInfo As Long
End Type
Const INPUT_KEYBOARD = 1
Sub MySendKey(bkey As Long)
'参数bkey传入要模拟按键的虚拟码即可模拟按下指定键
Dim GInput(0 To 1) As GENERALINPUT
Dim KInput As KEYBDINPUT
KInput.wVk = bkey '你要模拟的按键
KInput.dwFlags = 0 '按下键标志
GInput(0).dwType = INPUT_KEYBOARD
CopyMemory GInput(0).xi(0), KInput, Len(KInput) '这个函数用来把内存中KInput的数据复制到GInput
KInput.wVk = bkey
KInput.dwFlags = KEYEVENTF_KEYUP ' 释放按键
GInput(1).dwType = INPUT_KEYBOARD ' 表示该消息为键盘消息
CopyMemory GInput(1).xi(0), KInput, Len(KInput)
'以上工作把按下键和释放键共2条键盘消息加入到GInput数据结构中
SendInput 2, GInput(0), Len(GInput(0)) '把GInput中存放的消息插入到消息列队
End Sub
除了以上这些,用全局钩子也可以模拟键盘消息。如果你对windows中消息钩子的用法已经有所了解,那么你可以通过设置一个全局HOOK来模拟键盘消息,比如,你可以用WH_JOURNALPLAYBACK这个钩子来模拟按键。WH_JOURNALPLAYBACK是一个系统级的全局钩子,它和WH_JOURNALRECORD的功能是相对的,常用它们来记录并回放键盘鼠标操作。WH_JOURNALRECORD钩子用来将键盘鼠标的操作忠实地记录下来,记录下来的信息可以保存到文件中,而WH_JOURNALPLAYBACK则可以重现这些操作。当然亦可以单独使用WH_JOURNALPLAYBACK来模拟键盘操作。你需要首先声明SetWindowsHookEx函数,它可以用来安装消息钩子:
Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long,ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
展开全部
我想这主要是由于你是在Command1_Click子程序段下编程,当然只有在手动情况下好使了!
你应该在初始化后,立即把要显示的图像,发送到图像控件句柄中!
光是AutoRedraw为True,那么它也不会自动处理的!
你应该在初始化后,立即把要显示的图像,发送到图像控件句柄中!
光是AutoRedraw为True,那么它也不会自动处理的!
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
近来的高手,有没VB的学习的电子书,资料 网址什么的
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询