在游戏软件或者其他软件中都有很多条线程,我们用OD附加进程以后点快捷栏上的“T”可以看到下图中的线程
每条线程是独立的,但是虽然是独立的线程,也要有一定的原则,线程和线程之间不可以产生数据访问或则逻辑等冲突,否则会导致游戏软件崩溃以及不可预知的错误。
游戏自身的线程无需我们操心,早已经做了严格的处理。
但是在我们去调用以及测试游戏功能CALL的时候就不一样了。
我们去创建一个线程然后调用功能CALL,我们的这个线程就有可能与游戏本身的线程产生数据访问冲突导致游戏崩溃。
不定时性和不确定性是数据访问冲突崩溃的2个特点。
运气好可能很久不会出现,运气不好可能立刻崩溃。
那么怎么办呢?
这个时候就用到了主线程
因为主线程是有队列的,我们只要借助主线程帮我们调用功能CALL就不会产生数据访问冲突了。
知道了病症和原理
那么我们来看看怎么用代码去实现
首先我们要HOOK主线程
重置窗口回调函数,在窗口回调函数中调用的代码即相当于在主线程中执行
DWORD Call_Hook主线程()
{
HWND hGame=Call_获取窗口句柄();
DWORD ndThreadId=GetWindowThreadProcessId(hGame,NULL);
if(ndThreadId!=0)
{
g_Hook返回=SetWindowsHookEx(WH_CALLWNDPROC,Call_主线程回调函数,NULL,ndThreadId);
}
return 1;
}
这里面的SetWindowsHookEx 也可以用 SetwindowLong
也可以达到同样的效果
在我们不用的时候同样要记着卸载
DWORD Call_卸载Hook主线程()
{
UnhookWindowsHookEx(g_Hook返回);
return 1;
}
HOOK完主线程以后
我们就可以到窗口回调函数中写代码了
如下
//主线程回调函数
LRESULT CALLBACK Call_主线程回调函数(int nCode,WPARAM wParam,LPARAM lparam)
{
CWPSTRUCT *lpArg=(CWPSTRUCT*)lparam;//结构 hwnd message wParam lParam
if (nCode==HC_ACTION)//自己进程的消息
{
if (lpArg->hwnd==Call_获取窗口句柄()&&lpArg->message==g_My消息ID)//我们自己的消息
{
switch (lpArg->wParam)
{
T封包参数*封包;
case ID_发送明文包:
封包=(T封包参数*)lpArg->lParam;
Call_明文发包(封包->nd包长,封包->p);
return 1;
break;
}
}
}
return CallNextHookEx(g_Hook返回,nCode,wParam,lparam);
}
需要调用的时候只要向主线程发送消息即可
代码如下
Msg_发送明文包(包长,(char *)p);
明白了吗?
道理很简单
之前的线程中直接调用CALL
变成了现在的 向主线程发送消息 让窗口回调函数帮你调用 ,需要提前做的就是 重置窗口回调函数以及在窗口回调函数中写入你要调用的代码即可。