上个星期在Sourceforge的Feeling项目下新增加了一个org.eclipse.swt.extension子项目,意在增强SWT的本机功能。我一向是SWT的Fans,不过却很抵触大型的RCP项目,喜欢only dependent SWT。经过一个星期的努力,现在已经整合了在Win32平台下获取系统、磁盘、内存、CPU相关信息,注册表,以及系统钩子等功能,喜欢SWT的朋友可以试用。目前还没有放出一个版本,请通过sf的CVS下载代码:
cvs -d:pserver:anonymous@feeling.cvs.sourceforge.net:/cvsroot/feeling login
由于一直使用的都是Java,对Win32编程并不是非常熟悉。但局限于Java的功能,对我们有相当大的限制,IBM就屡屡向突破这个限制,因此产生了SWT。这里我重点想说的是怎么使用Win32的系统钩子。SWT里已经包含了大量的Win32函数,不过那都是局限于Eclipse的需要,如果Eclipse不需要,SWT是不予以优先考虑的。通过SWT我们很容易使用线程钩子监控自己程序的键盘鼠标事件,而且封装的很好。但是想使用系统钩子确是一件不可能的事情,先看看钩子的函数原型:
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
idHook -- 系统钩子类型,实际上是一个int值,具体的定义请看MSDN
lpfn -- 钩子回调函数指针,当收到钩子消息时就执行这个回调函数,回调函数有3个参数,不同类型的钩子这3个参数有不同的含义,具体请看MSDN。
hMod -- DLL实例句柄(我猜是这样,我不熟悉Win32API编程),当钩子为系统钩子时这个参数是必须的,如果是单个程序或者线程使用的钩子那么可以不用这个值。
dwThreadId -- 线程ID,如果是单个程序或者线程使用的钩子这个参数是必须的。
在SWT生成的DLL中,并没有系统钩子必须用到的hMod,并不像一般的DLL有DllMain入口可以接受到DLL实例句柄。因此我们只要在JNI下的C代码里添加这个DLL实例句柄就可以完成系统钩子的功能了:
#define Dll_Export __declspec(dllexport)
HINSTANCE instance = NULL;
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD ul_reason_for_call, LPVOID lpReserved)
{
instance = hInstance;
return TRUE;
}
Dll_Export HHOOK SetHook(int hookType,HOOKPROC hookproc)
{
return SetWindowsHookEx(hookType, hookproc, instance, NULL);
}
Dll_Export BOOL UnHook(HHOOK hook)
{
if(hook != NULL)
return UnhookWindowsHookEx(hook);
else
return 0;
}
#ifndef NO_SetSystemHook
JNIEXPORT jint JNICALL Swt_extension_NATIVE(SetSystemHook)
(JNIEnv *env, jclass that, jint arg0, jint arg1)
{
jint rc = 0;
rc = (jint)SetHook(arg0, (HOOKPROC)arg1);
return rc;
}
#endif
#ifndef NO_UnSystemHook
JNIEXPORT jboolean JNICALL Swt_extension_NATIVE(UnSystemHook)
(JNIEnv *env, jclass that, jint arg0)
{
jboolean rc = 0;
rc = (jboolean)UnHook((HHOOK)arg0);
return rc;
}
#endif 那么通过SWT来实现系统钩子有多大难度呢?各位看看代码就知道了:
Callback callback = new Callback (this, "keyHook", 3); //$NON-NLS-1$
int proc = callback.getAddress ();
hook = Extension.SetSystemHook(13, proc);
………………………………
int keyHook(int nCode,int wParam,int lParam)
{
int Result=OS.CallNextHookEx(hook,nCode,wParam,lParam);
………………
return Result;
}
很简单吧^_^