
HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,即它处理的消息类型
HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
// 或是一个由别的进程创建的线程的标识,
// lpfn必须指向DLL中的钩子子程。
// 除此以外,lpfn可以指向当前进程的一段钩子子程代码。
// 钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程的
DLL。
// 如果dwThreadId 标识当前进程创建的一个线程,
// 而且子程代码位于当前进程,hMod必须为NULL。
// 可以很简单的设定其为本应用程序的实例句柄。
DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符。
// 如果为0,钩子子程与所有的线程关联,即为全局钩子。
);
函数成功则返回钩子子程的句柄,失败返回NULL。
WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。
可以参考>
什么是句柄
先来看些权威的片断:
typedef
unsigned
int
HANDLE;
#define
DECLARE_HANDLE(name)
typedef
UINT
name
DECLARE_HANDLE(HMODULE);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HLOCAL);
DECLARE_HANDLE(HGLOBAL);
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HRGN);
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HMENU);
DECLARE_HANDLE(HACCEL);
DECLARE_HANDLE(HTASK);
#define
DECLARE_HANDLE(x)
typedef
WORD
x
//+-------------------------------------------------------------------------
//
DECLARE_HANDLE
Macro
//--------------------------------------------------------------------------
#ifndef
DECLARE_HANDLE
#define
DECLARE_HANDLE(name)
\
struct
name##__
{
DWORD
unused;
};
\
typedef
struct
name##__
_far
name
#endif
知道本质了吧~~~~
WINDOWS程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,WINDOWS
API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行 *** 作。
在<<WINDOWS编程短平快>>(南京大学出版社)一书中是这么说的:句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。
从上面的2个定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。在WINDOWS编程中会用到大量的句柄,比如:HINSTANCE(实例句柄),HBITMAP(位图句柄),HDC(设备描述表句柄),HICON(图标句柄)等等,这当中还有一个通用的句柄,就是HANDLE,比如下面的语句:
HINSTANCE
hInstance;
可以改成:
HANDLE
hInstance;
上面的2句语句都是对的。
一个WINDOWS应用程序可以用不同的方法获得一个特定项的句柄。许多API函数,诸如CreateWindow,GlobalAlloc,OpenFile的返回值都是一个句柄值。另外,WINDOWS也能通过应用程序的引出函数将一个句柄作为参数传送给应用程序,应用程序一旦获得了一个确定项的句柄,便可在WINDOWS环境下的任何地方对这个句柄进行 *** 作。其实句柄的大量使用已经影响到了每一个WINDOWS的程序设计。
句柄只有当唯一的确定了一个项目
PID是进程号!
说简单点,句柄无效出现这种提示,有三种可能:
1、软件有问题;
2、电脑有病毒;
3、系统有故障;
你可以把软件在别人的相同系统的电脑上装一下 ,如果不可以使用,你的软件有问题;
如果可以使用,你的电脑很有可能中毒了,格式化硬盘,重装系统吧;
所谓句柄实际上是一个数据,是一个Long (整长型)的数据;
句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等,WINDOWS句柄有点象C语言中的文件句柄;
从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样;
但是,也可能有一个名字和你一样的人,从数据类型上来看它只是一个16位的无符号整数,应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。
如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针;
我们知道,所谓指针是一种内存地址,应用程序启动后,组成这个程序的各对象是住留在内存的,如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象;
但是,如果您真的这样认为,那么您就大错特错了,我们知道,Windows是一个以虚拟内存为基础的 *** 作系统,在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要,对象被移动意味着它的地址变化了,如果地址总是如此变化,我们该到哪里去找该对象呢;
为了解决这个问题,Windows *** 作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的;
Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存,这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置,这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统;
句柄地址(稳定)→记载着对象在内存中的地址————→对象在内存中的地址(不稳定)→实际对象;
本质:WINDOWS程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,WINDOWS API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行 *** 作;
但是必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。
使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的 *** 作。
回调函数还与Hook函数相类似,Hook函数只是回调函数的一个特例。习惯上把与SetWindowsHookEx函数一起使用的回调函数称为钩子函数。也有人把利用VirtualQueryEx安装的函数称为钩子函数,不过这种叫法不太流行。
下面是一个动态库与应用程序之间,实现回调函数的例子,重在说明回调函数的实现机制,至于内部代码,根据自己程序需要来更改
步骤:
1、在动态库中:
11 声明应用程序中回调函数的原形,例子如下:
typedef int (WINAPI PFCALLBACK)(int Param1, int Param2);
22 定义回调函数类型:
PFCALLBACK gCallBack = 0;
33 写被应用程序调用的接口函数:
extern "C" void WINAPI TestCallBack(PFCALLBACK Func)
{
if(Func == NULL)
return;
gCallBack = Func;
DWORD ThreadID = 0;
HANDLE hThread = CreateThread(NULL, 0, Thread1, LPVOID(0), 0, &ThreadID);
return;
}
44 写Thread1这个过程:
DWORD WINAPI Thread1(
LPVOID lpParameter // thread data
)
{
TCHAR Buffer[256];
HDC hDC = GetDC(HWND_DESKTOP);
int Step=1;
MSG Msg;
DWORD StartTick;
//一个延时循环
for(;Step<200;Step++)
{
StartTick = GetTickCount();
/这一段为线程交出部分运行时间以让系统处理其他事务/
for(;GetTickCount()-StartTick<10;)
{
if(PeekMessage(&Msg,NULL,0,0,PM_NOREMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
/把运行情况打印到桌面,这是vcbear调试程序时最喜欢干的事情/
sprintf(Buffer,"Running %04d",Step);
if(hDC!=NULL)
TextOut(hDC,30,50,Buffer,strlen(Buffer));
}
/延时一段时间后调用回调函数/
(gCallBack)(Step,1);
/结束/
::ReleaseDC(HWND_DESKTOP,hDC);
return 0;
}
2、在应用程序中:
21 在头文件中,声明回调函数原形,并定义应用程序实例句柄:
typedef int (WINAPI PFCALLBACK)(int Param1, int Param2);
HINSTANCE m_handle;
22 在执行文件中加载动态库:
m_handle = LoadLibrary("CallBack_Dlldll");
23 在一个按钮事件中,调用动态库接口函数:
void CVC_CallBackDlg::OnCallBack()
{
// TODO: Add your control notification handler code here
typedef void (WINAPI PTestCallBack)(PFCALLBACK);
PTestCallBack addFun; //函数指针
addFun = (PTestCallBack)GetProcAddress(m_handle, "TestCallBack");
addFun(CBFunc);
}
24 写回调函数过程:
int WINAPI CBFunc(int Param1, int Param2)
{
int res = Param1 + Param2;
CHAR Buffer[256] = "";
sprintf(Buffer, "callback result = %d", res);
::MessageBox(NULL, Buffer, "Test", MB_OK); //演示回调函数被调用
return res;
}
25 在窗口退出时,释放应用程序实例句柄:
void CVC_CallBackDlg::OnCancel()
{
// TODO: Add extra cleanup here
FreeLibrary(m_handle);
CDialog::OnCancel();
}
至此,动态库与应用程序的整个回调函数实现过程,就实现了。
以上就是关于这句lHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf CallKeyHookProc, App.hInstance, 0)什么意思全部的内容,包括:这句lHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf CallKeyHookProc, App.hInstance, 0)什么意思、C#获取某应用程序窗体中控件的句柄、有谁知道进程中句柄和PID有什么区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)