SWT-Extension這個(gè)項(xiàng)目做了很久,但一直都沒(méi)有realease,只是個(gè)人做著玩玩,很重要的一個(gè)原因是對(duì)Windows System Hook的機(jī)制沒(méi)有能夠很好地實(shí)現(xiàn)出來(lái)。Hook本身不算是很難的技術(shù),在C++,C#里都能夠很容易的實(shí)現(xiàn),為什么運(yùn)用Java就那么困難呢?
首先當(dāng)然主要還是我個(gè)人對(duì)C++并不在行了,其次就是Java和C++交互的問(wèn)題了。要想通過(guò)C++把數(shù)據(jù)傳給Java,就要通過(guò)JNI標(biāo)準(zhǔn)的接口來(lái)實(shí)現(xiàn),也就是要通過(guò) JNIENV 來(lái)實(shí)現(xiàn),但是HookProc 這個(gè)CallBack 是給系統(tǒng)進(jìn)程調(diào)用的,不是給你Java調(diào)用的,你說(shuō)系統(tǒng)進(jìn)程調(diào)用了 HookProc 之后,沒(méi)法把這個(gè)事件傳遞給Java,那么還有一個(gè)方法,用Java不間斷的輪循Hook里的數(shù)據(jù),這倒是能實(shí)現(xiàn),網(wǎng)上也有一個(gè)老外的例子,但不好的地方就是當(dāng)我系統(tǒng)沒(méi)工作的時(shí)候,你Java還在那兒輪循我干嘛?這不是浪費(fèi)資源嗎?所以呢,這解鈴還需系鈴人,系統(tǒng)的事件還得讓系統(tǒng)來(lái)通知你才好。在Java里,有一個(gè)IO阻塞,比如當(dāng)調(diào)用System.in.read()的時(shí)候,系統(tǒng)就是等待你的輸入,如果你不輸入,系統(tǒng)就一直等著不工作。還有線程,有wait方法,非要等著其他的線程通過(guò)notify把你喚醒你才能工作。在C++里也有這么一套機(jī)制:CreateEvent 和WaitForSingleObject,也就是說(shuō)我先創(chuàng)建一個(gè)事件,然后將這個(gè)事件置于未激活狀態(tài),讓它一直等待,將線程阻塞住,當(dāng)HookProc被系統(tǒng)進(jìn)程調(diào)用的時(shí)候,就將這個(gè)事件激活,通知Java程序你可以開(kāi)始干活了,干完活以后再次被阻塞,直到這個(gè)Hook被uninstall掉。當(dāng)然這其中還有一些 C++ 代碼的細(xì)節(jié)性問(wèn)題,比如怎么讓不同的進(jìn)程共享同一個(gè)事件,這里要說(shuō)明的就是不同的進(jìn)程可以共享同一個(gè)事件,但是不能共享同一個(gè)事件句柄,同一個(gè)事件,在不同的進(jìn)程里有不同的句柄,句柄是不能跨進(jìn)程的。
我個(gè)人認(rèn)為Hook應(yīng)當(dāng)是SWT-Extension里一個(gè)很重要的組成部分,SWT本身只能實(shí)現(xiàn)線程鉤子,對(duì)于系統(tǒng)級(jí)的鉤子無(wú)能為力。因?yàn)橄到y(tǒng)機(jī)鉤子需要實(shí)現(xiàn)數(shù)據(jù)共享操作,還需要DLL入口句柄,這些我已都在SWT-Extension中實(shí)現(xiàn)了。唯一讓我遺憾的是沒(méi)有辦法實(shí)現(xiàn)日志鉤子,這是一個(gè)很有用的鉤子,可以用來(lái)記入當(dāng)前用戶行為的操作,然后重新演示,我想如果做自動(dòng)化測(cè)試這個(gè)會(huì)很有用,或者給游戲軟件練功什么的,呵呵。之所以不能實(shí)現(xiàn)是因?yàn)檫@個(gè)鉤子很特別,它要的不是DLL的句柄,而是應(yīng)用程序的句柄,這沒(méi)有辦法從Java程序里獲得,我試過(guò)javaw.exe,但是也不行,會(huì)導(dǎo)致系統(tǒng)假死。以后有時(shí)間在研究吧。
做完Hook,終于可以松一口氣,發(fā)一個(gè)小小的realease了,剩下的就是document工作要做了,一個(gè)枯燥無(wú)味的工作,就當(dāng)練習(xí)一下英語(yǔ)好了。
這里發(fā)一個(gè)Hook的截圖:

沒(méi)有了標(biāo)題欄的Eclipse
最新的Build和代碼也可以在 http://feeling.sf.net 上下載了。
首先當(dāng)然主要還是我個(gè)人對(duì)C++并不在行了,其次就是Java和C++交互的問(wèn)題了。要想通過(guò)C++把數(shù)據(jù)傳給Java,就要通過(guò)JNI標(biāo)準(zhǔn)的接口來(lái)實(shí)現(xiàn),也就是要通過(guò) JNIENV 來(lái)實(shí)現(xiàn),但是HookProc 這個(gè)CallBack 是給系統(tǒng)進(jìn)程調(diào)用的,不是給你Java調(diào)用的,你說(shuō)系統(tǒng)進(jìn)程調(diào)用了 HookProc 之后,沒(méi)法把這個(gè)事件傳遞給Java,那么還有一個(gè)方法,用Java不間斷的輪循Hook里的數(shù)據(jù),這倒是能實(shí)現(xiàn),網(wǎng)上也有一個(gè)老外的例子,但不好的地方就是當(dāng)我系統(tǒng)沒(méi)工作的時(shí)候,你Java還在那兒輪循我干嘛?這不是浪費(fèi)資源嗎?所以呢,這解鈴還需系鈴人,系統(tǒng)的事件還得讓系統(tǒng)來(lái)通知你才好。在Java里,有一個(gè)IO阻塞,比如當(dāng)調(diào)用System.in.read()的時(shí)候,系統(tǒng)就是等待你的輸入,如果你不輸入,系統(tǒng)就一直等著不工作。還有線程,有wait方法,非要等著其他的線程通過(guò)notify把你喚醒你才能工作。在C++里也有這么一套機(jī)制:CreateEvent 和WaitForSingleObject,也就是說(shuō)我先創(chuàng)建一個(gè)事件,然后將這個(gè)事件置于未激活狀態(tài),讓它一直等待,將線程阻塞住,當(dāng)HookProc被系統(tǒng)進(jìn)程調(diào)用的時(shí)候,就將這個(gè)事件激活,通知Java程序你可以開(kāi)始干活了,干完活以后再次被阻塞,直到這個(gè)Hook被uninstall掉。當(dāng)然這其中還有一些 C++ 代碼的細(xì)節(jié)性問(wèn)題,比如怎么讓不同的進(jìn)程共享同一個(gè)事件,這里要說(shuō)明的就是不同的進(jìn)程可以共享同一個(gè)事件,但是不能共享同一個(gè)事件句柄,同一個(gè)事件,在不同的進(jìn)程里有不同的句柄,句柄是不能跨進(jìn)程的。
我個(gè)人認(rèn)為Hook應(yīng)當(dāng)是SWT-Extension里一個(gè)很重要的組成部分,SWT本身只能實(shí)現(xiàn)線程鉤子,對(duì)于系統(tǒng)級(jí)的鉤子無(wú)能為力。因?yàn)橄到y(tǒng)機(jī)鉤子需要實(shí)現(xiàn)數(shù)據(jù)共享操作,還需要DLL入口句柄,這些我已都在SWT-Extension中實(shí)現(xiàn)了。唯一讓我遺憾的是沒(méi)有辦法實(shí)現(xiàn)日志鉤子,這是一個(gè)很有用的鉤子,可以用來(lái)記入當(dāng)前用戶行為的操作,然后重新演示,我想如果做自動(dòng)化測(cè)試這個(gè)會(huì)很有用,或者給游戲軟件練功什么的,呵呵。之所以不能實(shí)現(xiàn)是因?yàn)檫@個(gè)鉤子很特別,它要的不是DLL的句柄,而是應(yīng)用程序的句柄,這沒(méi)有辦法從Java程序里獲得,我試過(guò)javaw.exe,但是也不行,會(huì)導(dǎo)致系統(tǒng)假死。以后有時(shí)間在研究吧。
做完Hook,終于可以松一口氣,發(fā)一個(gè)小小的realease了,剩下的就是document工作要做了,一個(gè)枯燥無(wú)味的工作,就當(dāng)練習(xí)一下英語(yǔ)好了。
這里發(fā)一個(gè)Hook的截圖:

沒(méi)有了標(biāo)題欄的Eclipse