1. 程式人生 > >追逐自己的夢想----------輔助製作第八課:利用SetWindowsHook將程序注入遊戲主執行緒來解決資源衝突的問題

追逐自己的夢想----------輔助製作第八課:利用SetWindowsHook將程序注入遊戲主執行緒來解決資源衝突的問題

本節課中,我們需要學習利用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防止重複定義