令人头痛的WH_CBT钩子,使窗口前置——泪水+汗水的赞歌
一、工作中遇到一個(gè)問(wèn)題:
1、需要讓某個(gè)特定的窗口不被最小化、不被阻擋、不失去焦點(diǎn)(因?yàn)橛休斎?#xff09;;
2、由某個(gè)服務(wù)或進(jìn)程來(lái)自動(dòng)篩選和控制。
本來(lái)覺得用幾個(gè)windows API就OK了,誰(shuí)知道弄了好長(zhǎng)好長(zhǎng)的時(shí)間,崩潰了N次,直到現(xiàn)在..............依舊不敢100%確定,唉!
二、思路
1、FindWindow而后前置SetForegroundWindow
——總感覺似乎不妥,野蠻暴力,還得檢索window句柄列表
2、插個(gè)全局鉤子,自行判斷是否前置
——感覺好一點(diǎn),沒那么暴力了,不過(guò)問(wèn)題來(lái)了:用什么鉤子?
三、實(shí)踐
1、找啊找,找遍了整個(gè)屋子,終于找著了這本《阿里波特》——HCBT_CREATEWND,可以監(jiān)視窗口創(chuàng)建——心花怒放!
——于是開始了一周的調(diào)試——注定要燒腦到死——跑偏了。
2、失敗!失敗!失敗.........!
3、終于在崩潰前夕,不經(jīng)意間發(fā)現(xiàn)了有個(gè)叫HCBT_ACTIVATE的家伙——她居然在燈火闌珊處好久了!小試一下,居然比那個(gè)桀驁不馴的HCBT_CREATEWND乖巧多了!不會(huì)分辨不清窗口和菜單、不會(huì)去分辨對(duì)話框窗口........,愛死你了!
好吧,就你了!
4、天真地認(rèn)為花兩小時(shí)調(diào)試一下就OK了..............圖樣圖森破
5、要么找不到句柄1428,要么126、193.............
6、又一次在崩潰的邊緣發(fā)現(xiàn)她還有一閨蜜——LoadLibraryEx,那個(gè)LoadLibrary已經(jīng)被Win7封印了!(開發(fā)環(huán)境win10卻好好的)好吧,有新歡就新歡吧,聽你的!
噢,差點(diǎn)忘了#pragma data_seg,也如影隨形,照顧不周,她就會(huì)搗亂,好吧,咱倆不熟,先學(xué)習(xí)研究下.......
7、啊?程序不能移植?這沒有道理啊?肯定是目標(biāo)機(jī)缺少運(yùn)行庫(kù)環(huán)境!我裝——
8、VC++運(yùn)行庫(kù)合集——利刃吶!
——什么!還不行?!
9、...................................我還是程序員嗎?
10、再去崩潰的邊緣溜達(dá)溜達(dá)吧..............3、4天了,怎么跟人交差啊!
11、傳說(shuō)中有個(gè)叫“Release版本”的朋友,可我一直沒有聯(lián)系過(guò)!不經(jīng)意間,他似乎.............
12、試試看吧,也許呢?...............朋友就是朋友啊,夠意思!
13、哈哈,鉤子跑起來(lái)了,貌似成功了!
14、..................怎么?鉤子使性子?一會(huì)管用一會(huì)不管用?
15、家法伺候中.....................
16、我知道了不是你的錯(cuò),你是32位的,還得有64位的,還得有32和64位的注入程序——好吧,給你倆克隆個(gè)雙胞胎兄弟!——等等,我先研究下clone技術(shù).................
17、什么?克隆了還不老實(shí)?...............................
——一會(huì)讓我的VS窗口前置,一會(huì)讓我的瀏覽器前置,當(dāng)我的strstr函數(shù)不存在啊?
18、這下百度幫不了了,怎么回事?宣告是系統(tǒng)bug嗎?
19、找bug,找bug,找bug,找bug,找bug,找bug,找bug,找bug,找bug,找......................
20、天道酬勤啊,原來(lái)是你——局部變量const,真不明白strstr函數(shù)就那么矯情,非要const參數(shù)干嗎,可傳個(gè)非const似乎也行........
21、于是經(jīng)過(guò)很久很久的多次崩潰,鉤子就成了下面這個(gè)樣子——
#include <windows.h> #include <iostream> #include <Psapi.h> #include <string> //#define _WIN32_WINNT 0x500using namespace std; #pragma data_seg("SharedDataName") HHOOK hooker=NULL; HWND ghwnd = NULL; DWORD pid = -1; //string TargetName = "AppFiles"; const char* target = "AppFiles";//TargetName.c_str(); #pragma data_seg() #pragma comment(linker,"/section:SharedDataName,rws")HWND privateHwnd;extern "C" __declspec(dllexport) LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam); extern "C" __declspec(dllexport) HHOOK setHookDll(); extern "C" __declspec(dllexport) BOOL unHookDll(); extern "C" __declspec(dllexport) void getPid(DWORD id); extern "C" __declspec(dllexport) void getPName(string name);BOOL APIENTRY DllMain(HMODULE hModule/* hModule */, DWORD ul_reason_for_call, LPVOID /* lpReserved */lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:privateHwnd = NULL;break;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE; }void CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nTimerid, DWORD dwTime);extern "C" __declspec(dllexport) LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) {if (nCode<0)return CallNextHookEx(hooker, nCode, wParam, lParam);tagMSG* msg;msg = (tagMSG*)lParam;switch (nCode){case HC_ACTION:break;case HCBT_CREATEWND:break;case HCBT_ACTIVATE:{HWND currentHwnd = (HWND)wParam;DWORD processID = NULL;GetWindowThreadProcessId(currentHwnd, &processID);HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);//LPSTR procName;TCHAR procName[MAX_PATH] = { 0 };GetProcessImageFileName(hProcess, procName, MAX_PATH);char* source = procName;if (strstr(source, target) != NULL){ghwnd = currentHwnd;privateHwnd = currentHwnd;KillTimer(currentHwnd, 1);//MessageBox(currentHwnd, source, target, MB_OK);SetTimer(currentHwnd, 1, 1000, (TIMERPROC)TimerProc);}break;}default:break;}return CallNextHookEx(hooker, nCode, wParam, lParam); }extern "C" __declspec(dllexport) HHOOK setHookDll() {hooker = SetWindowsHookEx(WH_CBT, HookProc, (HINSTANCE)GetModuleHandle("winhook.dll"), 0);//64位 用winhook64.dllreturn hooker; }extern "C" __declspec(dllexport) BOOL unHookDll() {KillTimer(privateHwnd, 1);bool unHk = UnhookWindowsHookEx(hooker);return unHk; }extern "C" __declspec(dllexport) void getPid(DWORD id) {pid = id; }extern "C" __declspec(dllexport) void getPName(string name) {//TargetName = name; }void _stdcall CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nTimerid, DWORD dwTime) {SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOMOVE);//BringWindowToTop(currentHwnd);//SetFocus(currentHwnd);//SetActiveWindow(currentHwnd);PostMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, NULL);HWND hForeWnd = ::GetForegroundWindow();DWORD dwForeID = ::GetWindowThreadProcessId(hForeWnd, NULL);DWORD dwCurID = ::GetCurrentThreadId();::AttachThreadInput(dwCurID, dwForeID, TRUE);SetForegroundWindow(hWnd);PostMessage(hWnd, WM_SETFOCUS, NULL, NULL);return; }22、不過(guò)在前置窗口并獲取焦點(diǎn)的問(wèn)題上倒數(shù)第三行的postmessage,以及前面的SetFocus似乎不怎么管用,在實(shí)際體驗(yàn)中感覺還是有小問(wèn)題,我是沒著了。
四、小記
1、微軟前置個(gè)窗口怎么就那么累呢?
2、指定窗口獲取個(gè)焦點(diǎn)怎么就那么費(fèi)勁呢?死活就是不認(rèn)。
3、非共享代碼段似乎也會(huì)出問(wèn)題,但不確認(rèn)。
總結(jié)
以上是生活随笔為你收集整理的令人头痛的WH_CBT钩子,使窗口前置——泪水+汗水的赞歌的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 家用食材净化器什么牌子好,家用食材净化器
- 下一篇: 《JAVA: 学习导图》