追逐自己的夢想----------輔助製作第八課:利用SetWindowsHook將程序注入遊戲主執行緒來解決資源衝突的問題
阿新 • • 發佈:2019-02-08
本節課中,我們需要學習利用SetWindowsHook來注入主執行緒,然後利用多執行緒的原理來解決資源衝突的問題。
1.注入的原因:不同的執行緒在訪問同一個共享資料的時候,如果沒有同步處理,就會造成錯誤,從而導致程式崩潰,所以我們可以給自己編寫的多執行緒,並且加上一些同步出來,然後再將dll注入到遊戲的主執行緒中,就可以解決資源衝突的問題。
我們要用到的函式是SetWindowsHook(),具體介紹看MSDN
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
具體程式碼如下:
#pragma once #ifndef HookMainthread #define HookMainthread #include<Windows.h> #include"BaseGameData.h" class Threaddata :public BaseData{ public: Threaddata(); ~Threaddata(); }; extern Threaddata *pdata; extern DWORD BaseGameMainhwd; #define MSG_USEGOODS 1 HWND GetGamewndHandle();//獲取遊戲控制代碼 DWORD HookMainThread(); //掛載鉤子 DWORD UnHookMainThread();// 解除安裝鉤子 DWORD MsgUseGoodsForName(char *szpName); //訊息傳遞 #endif // !HookMainthread
#include"HookMainWndThread.h" Threaddata *pdata; DWORD BaseGameMainhwd = pdata->GetMainWndHangle(); Threaddata::Threaddata(){ } Threaddata::~Threaddata(){ } HWND GetGamewndHandle(){ //獲取遊戲控制代碼 HWND hGame; try{ hGame = *(HWND*)BaseGameMainhwd; } catch (...){ hGame = NULL; } return hGame; } HHOOK g_hhkGame = NULL; //全域性變數,儲存setwindowshook的返回值 const DWORD MyMsgCode = RegisterWindowMessageA("MyMsgCode"); //註冊訊息 //回撥函式 LRESULT CALLBACK GameWndProc(int nCode, WPARAM wParam, LPARAM lParam ){ CWPSTRUCT *lpArg = (CWPSTRUCT*)lParam; //資料結構,用來獲取lparam引數中的資料 if (nCode == HC_ACTION){ if (lpArg->hwnd == GetGamewndHandle() && lpArg->message == MyMsgCode){ switch (lpArg->wParam){ case MSG_USEGOODS: DbgPrint_String("使用物品%s", (char*)lpArg->lParam); PacketData tBackList; tBackList.UseGoodsByName((char*)lpArg->lParam); break; } return 1; } } return CallNextHookEx(g_hhkGame, nCode, wParam, lParam); } //掛接到主執行緒 DWORD HookMainThread(){ HWND hGame = GetGamewndHandle(); DWORD ndThreadID = GetWindowThreadProcessId(hGame, NULL); if (ndThreadID != 0){ SetWindowsHookEx(WH_CALLWNDPROC, GameWndProc, NULL, ndThreadID); } return 1; } //解除安裝主執行緒 DWORD UnHookMainThread(){ UnhookWindowsHookEx(g_hhkGame); return 1; } //傳遞訊息 DWORD MsgUseGoodsForName(char *szpName){ ::SendMessageA(GetGamewndHandle(), MyMsgCode, MSG_USEGOODS, (LPARAM)szpName); return 1; }
然後在對話方塊類建立3個按鈕分別用來掛接主執行緒,解除安裝主執行緒,和使用物品就可以了
void CMainDialog::OnBnClickedButton2()
{
// TODO: 掛載到主執行緒
//pHookThread->HookMainThread();
HookMainThread();
}
void CMainDialog::OnBnClickedButton3()
{
// TODO: 解除安裝windowsHook
//pHookThread->UnHookMainThread();
UnHookMainThread();
}
void CMainDialog::OnBnClickedButton4()
{
// TODO: 物品使用
//pHookThread->msgUseGoodsByName("金創藥(小)");
MsgUseGoodsForName("金創藥(小)");
}
以上程式碼就完成了將遊戲掛載到主執行緒中,其中特別注意的是全域性變數最好放到cpp檔案了,還有就是宣告需要加上extern防止重複定義