重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
WINDOWS的钩子函数可以认为是WINDOWS的主要特性之一。利用它们,您可以捕捉您自己进程或其它进程发生的事件。通过“钩挂”,您可以给WINDOWS一个处理或过滤事件的回调函数,该函数也叫做“钩子函数”,当每次发生您感兴趣的事件时,WINDOWS都将调用该函数。一共有两种类型的钩子:局部的和远程的。
公司主营业务:成都网站制作、网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联公司是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联公司推出沐川免费做网站回馈大家。
局部钩子仅钩挂您自己进程的事件。
远程的钩子还可以将钩挂其它进程发生的事件。远程的钩子又有两种:
基于线程的 它将捕获其它进程中某一特定线程的事件。简言之,就是可以用来观察其它进程中的某一特定线程将发生的事件。
系统范围的 将捕捉系统中所有进程将发生的事件消息。 当您创建一个钩子时,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当一个事件发生时,如果您安装的是一个局部钩子,您进程中的钩子函数将被调用。如果是一个远程钩子,系统就必须把钩子函数插入到其它进程的地址空间,要做到这一点要求钩子函数必须在一个动态链接库中,所以如果您想要使用远程钩子,就必须把该钩子函数放到动态链接库中去。当然有两个例外:工作日志钩子和工作日志回放钩子。这两个钩子的钩子函数必须在安装钩子的线程中。原因是:这两个钩子是用来监控比较底层的硬件事件的,既然是记录和回放,所有的事件就当然都是有先后次序的。所以如果把回调函数放在DLL中,输入的事件被放在几个线程中记录,所以我们无法保证得到正确的次序。故解决的办法是:把钩子函数放到单个的线程中,譬如安装钩子的线程。
钩子一共有14种,以下是它们被调用的时机:
WH_CALLWNDPROC 当调用SendMessage时
WH_CALLWNDPROCRET 当SendMessage的调用返回时
WH_GETMESSAGE 当调用GetMessage 或 PeekMessage时
WH_KEYBOARD 当调用GetMessage 或 PeekMessage 来从消息队列中查询WM_KEYUP 或 WM_KEYDOWN 消息时
WH_MOUSE 当调用GetMessage 或 PeekMessage 来从消息队列中查询鼠标事件消息时
WH_HARDWARE 当调用GetMessage 或 PeekMessage 来从消息队列种查询非鼠标、键盘消息时
WH_MSGFILTER 当对话框、菜单或滚动条要处理一个消息时。该钩子是局部的。它时为那些有自己的消息处理过程的控件对象设计的。
WH_SYSMSGFILTER 和WH_MSGFILTER一样,只不过是系统范围的
WH_JOURNALRECORD 当WINDOWS从硬件队列中获得消息时
WH_JOURNALPLAYBACK 当一个事件从系统的硬件输入队列中被请求时
WH_SHELL 当关于WINDOWS外壳事件发生时,譬如任务条需要重画它的按钮.
WH_CBT 当基于计算机的训练(CBT)事件发生时
WH_FOREGROUNDIDLE 由WINDOWS自己使用,一般的应用程序很少使用
WH_DEBUG 用来给钩子函数除错
附:如何使用钩子函数(接收到字母A按下时,窗体由最小化弹出的完整的代码)
Public Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, _
ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Public 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
Public Const WH_KEYBOARD = 2
Public Const KEY_WINSTART = 91
Public Const KEY_WINMENU = 93
Global hHook As Long
Public Function KeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If nCode = 0 Then
If wParam = KEY_WINMENU Or wParam = KEY_WINSTART Then
If (lParam And HC0000000) = 0 Then
MsgBox "", , ""
KeyboardProc = 1
Exit Function
End If
End If
End If
KeyboardProc = CallNextHookEx(hHook, nCode, wParam, lParam)
End Function
Option Explicit
Private Sub Command1_Click()
form2.Show 1
End Sub
Private Sub form_Load()
hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, 0, App.ThreadID)
Me.Show
End Sub
Private Sub form_Unload(Cancel As Integer)
Call UnhookWindowsHookEx(hHook)
End Sub
例子:
#!/usr/bin/python
# Filename: class_init.py
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print Hello, my name is, self.name
p = Person(Swaroop)
p.sayHi()
这个例子中就是在init方法中定义了参数name,然后调用的时候直接用类名person带上传参swaroop就行了,swaroop参数就会传递给sayhi(),整个流程就对应c中的构造函数。
然后说钩子,其实就是实现一种内操作,有子进程的意思但又不是,至于装饰函数是不是钩子好像没官方说法,我认为可以算是。装饰器就是把一个函数对象返回给另一个函数来实现既定的功能,其实就是一种内操作。
PS:很多东西都是相关的,比如方法和它的具体实现功能,等你用到它的功能以后就很好理解了,单纯的研究理论也没什么意思。尤其是这种比较抽象的概念。
钩子函数是用来给系统回调的. 简单的说就是你注册一个钩子以后.发生钩子注册的事件. 系统就调用你注册的钩子函数并传递参数给你. 比如你注册了一个键盘钩子, 当用户按下XX键的时候系统就调用你注册的钩子函数. 并且把用户按下了哪些键当作参数传递过来. XX小马就是用这个来邪恶的
麻烦采纳,谢谢!
问得不清楚,所以不懂怎么回答这个区别。
所谓回调函数,一般就是把函数的地址作为参数传进去,让调用的函数在内部可以调用这个函数。
例子:
void CALLBACK fun(){...} 这是一个函数,回调函数
void AAA(int a, Fun* p); 这是一个普通函数,但第二个参数是fun
AAA(5, fun);
钩子函数,严格算起来,也算是回调函数的一种。但钩子函数是针对的截取的,当你使用了钩子之后,每当触发到相对应的消息,系统就会先“执行你写的回调函数”。
即原本是:系统--目标函数
使用钩子就变成:系统--你写的回调函数--目标函数
大概原理就是这样子。就不知道你对函数与钩子的了解水平如何了
大大提供了灵活性。
@before_first_request
在对应用程序实例的第一个请求之前注册要运行的函数,只会运行一次
@before_request
在每个请求之前注册一个要运行的函数,每一次请求都会执行一次
@after_request
在每个请求之后注册一个要运行的函数,每次请求完成后都会执行。
需要接受一个Response对象作为参数,并返回一个新的Response对象,或者返回接收的Response对象
@teardown_request
注册在每一个请求的末尾,不管是否有异常,每次请求的最后都会执行。
@context_processor
上下文处理器,返回的字典可以在全部的模板中使用
@template_filter('xxxxxx')
增加模板过滤器,可以在模板中使用该函数,后面的参数是名称,在模板中用到
@errorhandler(400)
发生一些异常时,比如404,500,或者抛出异常(Exception)之类的,就会自动调用该钩子函数
1.发生请求错误时,框架会自动调用相应的钩子函数,并向钩子函数中传入error参数
2.如果钩子函数没有定义error参数,就会报错
3.可以使用abort函数来手动终止请求抛出异常,如果要是发生参数错误,可以abort(404)之类的
a. app.py
b. hooks.py
c. main.py
看别人的写法,创建hooks.py后,直接在该文件import app后,然后写钩子函数,在访问过程中钩子函数是生效,但我一直失败,没办法只能更改写法了。
先在app.py中创建app对象,然后在hooks.py中import app写好钩子函数,最后在main.py中import app时不再是从app.py中了,而是从hooks.py中import,那么在这个过程中hooks.py文件就加载了,钩子函数也就生效了。
RTT在空闲的时候可以使用钩子函数执行些简单的任务,例如LED闪烁之类的程序,利用这个功能我们可以做个工作状态指示灯
要使用钩子必须在配置里打开钩子的配置,在rt-config.h里添加HOOK宏定义(如果没有的话)
#define RT_USING_HOOK
然后在应用程序里设置钩子函数
#ifdef RT_USING_HOOK
rt_thread_idle_sethook(rt_hw_led_flash);
#endif
下面就是该怎样实现这个函数了
void rt_hw_led_flash(void)
{
rt_uint32_t i;
rt_hw_led_init();
while (1)
{
for(i = 0; i 2700000; i++); //500ms
GPIO_WriteBit(state_led_gpio, state_led_pin, (BitAction)(1-GPIO_ReadOutputDataBit(state_led_gpio, state_led_pin)));
}
}
这样写过之后,在系统空闲的时候就会执行这个函数,当然,如果系统繁忙的时候是不会进入这个idel任务的,不过如果系统一直处于繁忙的状态就是有问题了
另外一点记住,在这个函数里不能调用系统提供的使线程挂起的函数
例如:
rt thread delay,
rt sem take
等
while (1)
{
for(i = 0; i 2700000; i++); //500ms
GPIO_WriteBit(state_led_gpio, state_led_pin, (BitAction)(1-GPIO_ReadOutputDataBit(state_led_gpio, state_led_pin)));
}
关键是这个while(1)没跳出的,所以全部在这里执行了。
好像还有同学对其中一些并不是完全清楚,所以继续解析下,当做结贴:
1. idle线程是系统中最后一道防线,它将是系统中,如果无其他事可干时的最后能够运行的线程。
-- 所以idle线程不应该被阻塞。如果你有自己的线程能够成为这最后一道防线,那么这个限制将不存在。而对于一些原来系统中放在idle线程中做的工作(例如原来的最终的线程删除动作),在0.4.x中,可以手工调用rt_thread_idle_excute函数来执行。
2. 当系统空闲的时候,idle线程将执行这个钩子函数。
假设钩子函数一次运行会执行1ms,如果idle线程有机会运行200ms,那么钩子函数将被调用200次。
3. 钩子函数运行时,不应该把idle线程总是纠结在这个函数中运行,必须要让idle线程有机会去运行rt_thread_idle_excute函数(因为还有一些事情等待idle线程去处理)。
-- 所以在钩子函数中,不应该使用while(1);的方式。
while(1)
{
if ( indicator == RT_TRUE)
{
....do something
}
else
delay(20ms)
}
这样那20ms会执行idle线程吧,问题是idle 20ms够吗,如果我改20ms为5ms呢?
如果没有其他线程处理事务,将转换到idle线程去,通常idle线程中的系统任务会在0.xx ms以内执行完毕