一、工作中遇到一个问题:
1、需要让某个特定的窗口不被最小化、不被阻挡、不失去焦点(因为有输入);
2、由某个服务或进程来自动筛选和控制。
本来觉得用几个windows API就OK了,谁知道弄了好长好长的时间,崩溃了N次,直到现在..............依旧不敢100%确定,唉!
二、思路
1、FindWindow而后前置SetForegroundWindow
——总感觉似乎不妥,野蛮暴力,还得检索window句柄列表
2、插个全局钩子,自行判断是否前置
——感觉好一点,没那么暴力了,不过问题来了:用什么钩子?
三、实践
1、找啊找,找遍了整个屋子,终于找着了这本《阿里波特》——HCBT_CREATEWND,可以监视窗口创建——心花怒放!
——于是开始了一周的调试——注定要烧脑到死——跑偏了。
2、失败!失败!失败.........!
3、终于在崩溃前夕,不经意间发现了有个叫HCBT_ACTIVATE的家伙——她居然在灯火阑珊处好久了!小试一下,居然比那个桀骜不驯的HCBT_CREATEWND乖巧多了!不会分辨不清窗口和菜单、不会去分辨对话框窗口........,爱死你了!
好吧,就你了!
4、天真地认为花两小时调试一下就OK了..............图样图森破
5、要么找不到句柄1428,要么126、193.............
6、又一次在崩溃的边缘发现她还有一闺蜜——LoadLibraryEx,那个LoadLibrary已经被Win7封印了!(开发环境win10却好好的)好吧,有新欢就新欢吧,听你的!
噢,差点忘了#pragma data_seg,也如影随形,照顾不周,她就会捣乱,好吧,咱俩不熟,先学习研究下.......
7、啊?程序不能移植?这没有道理啊?肯定是目标机缺少运行库环境!我装——
8、VC++运行库合集——利刃呐!
——什么!还不行?!
9、...................................我还是程序员吗?
10、再去崩溃的边缘溜达溜达吧..............3、4天了,怎么跟人交差啊!
11、传说中有个叫“Release版本”的朋友,可我一直没有联系过!不经意间,他似乎.............
12、试试看吧,也许呢?...............朋友就是朋友啊,够意思!
13、哈哈,钩子跑起来了,貌似成功了!
14、..................怎么?钩子使性子?一会管用一会不管用?
15、家法伺候中.....................
16、我知道了不是你的错,你是32位的,还得有64位的,还得有32和64位的注入程序——好吧,给你俩克隆个双胞胎兄弟!——等等,我先研究下clone技术.................
17、什么?克隆了还不老实?...............................
——一会让我的VS窗口前置,一会让我的浏览器前置,当我的strstr函数不存在啊?
18、这下百度帮不了了,怎么回事?宣告是系统bug吗?
19、找bug,找bug,找bug,找bug,找bug,找bug,找bug,找bug,找bug,找......................
20、天道酬勤啊,原来是你——局部变量const,真不明白strstr函数就那么矫情,非要const参数干吗,可传个非const似乎也行........
21、于是经过很久很久的多次崩溃,钩子就成了下面这个样子——
#include
#include
#include
#include
//#define _WIN32_WINNT 0x500
using 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.dll
return 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;
}
四、小记
1、微软前置个窗口怎么就那么累呢?
2、指定窗口获取个焦点怎么就那么费劲呢?死活就是不认。
3、非共享代码段似乎也会出问题,但不确认。