前些日子一直忙,也没来看看,说要给出代码和方法的一直没有给出来请大家见谅,今天给出来!
声明:我不是做游戏外挂的,所以对外挂部分还比较薄弱,没做,只做实现窗口这一块!
1.先看实现的图片,等下慢慢解释。
2.首先解释要如何启动诸仙的进程。
我们要想拥有自己的窗口,那么就必须在诸仙的进程启动之前得到Direct3DCreate8接口(诸仙用Direct3D8)。所以启动过程如下:
//启动诸仙并获取诸仙进程句柄
ZhuXianProc.OpenExe("C://游戏目录//诛仙//element//elementclient.exe");
if(!ZhuXianProc.GetProcess())
{
MessageBox(NULL,
" 无法正常启动《诸仙》主程序/n/n获取帮助请与本工作室技术人员联系",
"天涯工作室程序运行错误提示!",MB_OK);
return TRUE;
}
//在程序运行之前先HOOK住所需要HOOK的API
HookApi("C://游戏目录//诛仙//element//elementclient.exe","C://游戏目录//诛仙//element//ZxDll.dll");
ZhuXianFunc();
ZhuXianProc.CloseAllHandle();
关于ZhuXianProc是一个CGetProc类型,这个类主要是打开进程和取得进程的一些信息,GetProcess()取的改进程的句柄。这个类里面要解释下的是:
void CGetProc::OpenExe(CString str)
{
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
CreateProcess(str,NULL,NULL,FALSE,NULL,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
}
“CREATE_SUSPENDED”指明该进程并不是一开始就让他运行,原因是我们要想得到Direct3DCreate8接口就必须在运行进程之前注入我们的DLL,并让我们的DLL里的HOOK Direct3DCreate8接口跑到他的初始化之前。
我们来看看HookApi()的内容:
bool CUIThread::HookApi(char* pszFileExe,char* pszFileDll)
{
//让程序启动的时候JMP到自己的DLL中去
HANDLE hProcess = ZhuXianProc.GetProcess();
// 在目标进程申请空间,存放字符串pszDllName,作为远程线程的参数
int cbSize = (strlen(pszFileDll) + 1);
LPVOID lpRemoteDllName = ::VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
::WriteProcessMemory(hProcess, lpRemoteDllName, pszFileDll, cbSize, NULL);
// 取得LoadLibraryA函数的地址,我们将以它作为远程线程函数启动
HMODULE hModule=::GetModuleHandle ("kernel32.dll");
LPTHREAD_START_ROUTINE pfnStartRoutine = (LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "LoadLibraryA");
// 启动远程线程
::ResumeThread(ZhuXianProc.GetThread());
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
if(hRemoteThread == NULL)
{
::CloseHandle(hProcess);
return FALSE;
}
::CloseHandle(hRemoteThread);
return TRUE;
}
这段关键是在:
// 启动远程线程
::ResumeThread(ZhuXianProc.GetThread());
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
必须这样,ResumeThread诸仙进程之后立即启动我们的DLL。呵呵,也不能弄反,如果进程没启动,我们注入的DLL就启动了,进程可能就崩溃了。
在这里有个小技巧,诸仙进程启动不代表就立即进行Direct3DCreate8初始化,他还有些事情要做,到他初始化的时候我们的DLL早就跑了一段了:)。
3.来看看我们的重点,我们注入的ZXDLL.DLL到底做了些什么事情。
#pragma comment(lib, "d3d8.lib")
// CZxDllApp
BEGIN_MESSAGE_MAP(CZxDllApp, CWinApp)
END_MESSAGE_MAP()
// CZxDllApp 构造
CZxDllApp::CZxDllApp()
{
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一个 CZxDllApp 对象
CZxDllApp theApp;
CAPIHook hookapi2("d3d8.dll","Direct3DCreate8",(PROC)NewDirect3DCreate8);
// CZxDllApp 初始化
BOOL CZxDllApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
看完DLL的这一段小程序,基本上是VC向导完成的,只有一句:
CAPIHook hookapi2("d3d8.dll","Direct3DCreate8",(PROC)NewDirect3DCreate8);
这句在DLL一运行的时候他就运行了,并把Direct3DCreate8给变成了新的入口地址NewDirect3DCreate8了,那么当诸仙运行的时候这个函数就跑到我们的NewDirect3DCreate8里来了,呵呵,正好,我们抓住了Direct3DCreate8接口了,来我们一起看看NewDirect3DCreate8函数里的内容。
IDirect3D8 * WINAPI NewDirect3DCreate8(UINT SDKVersion)
{
static int count = 0;
static IDirect3D8* test = NULL;
hookapi2.Unhook();
IDirect3D8 * m = Direct3DCreate8(SDKVersion);
hookapi2.Rehook();//程序一共3个3维平面驱动
count++;
if(count==2){//1,窗口模式请用2,全屏模式请用3
lpD3D = m;
//替换VTable,实现对IDirect3Draw 的 COM接口的挂钩
NewlpD3d = new MyIDirect3D8;
m = (IDirect3D8*)NewlpD3d;
}
return m;
}
呵呵,诸仙对IDirect3D8接口其实是驱动了3次,我没查出来第一次是干什么的,但是后两次一个是在窗口模式下用的,一个是在全屏模式下用的。光得到IDirect3D8接口是没用的这里我们还要进行COM HOOK 获得Direct3DDevice8(D3D 设备) 的接口的指针从而得到我们的Render该放到什么地方。
COM HOOK其实就是写一个同样的类用来替换COM的VTable,不做详细的解释,实在搞不懂就google(俺也是这么得来的:))。MyIDirect3D8就是一个新的IDirect3D8类,他是从IDirect3D8继承来的,定义如下:
class MyIDirect3D8 : public IDirect3D8
{
public:
HRESULT APIENTRY QueryInterface(REFIID riid, void** ppvObj);
ULONG APIENTRY AddRef();
ULONG APIENTRY Release();
/*** IDirect3D8 methods ***/
HRESULT APIENTRY RegisterSoftwareDevice(void* pInitializeFunction);
UINT APIENTRY GetAdapterCount();
HRESULT APIENTRY GetAdapterIdentifier(UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER8* pIdentifier);
UINT APIENTRY GetAdapterModeCount(UINT Adapter);
HRESULT APIENTRY EnumAdapterModes(UINT Adapter,UINT Mode,D3DDISPLAYMODE* pMode);
HRESULT APIENTRY GetAdapterDisplayMode(UINT Adapter,D3DDISPLAYMODE* pMode);
HRESULT APIENTRY CheckDeviceType(UINT Adapter,D3DDEVTYPE CheckType,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL Windowed);
HRESULT APIENTRY CheckDeviceFormat(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat);
HRESULT APIENTRY CheckDeviceMultiSampleType(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType);
HRESULT APIENTRY CheckDepthStencilMatch(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat);
HRESULT APIENTRY GetDeviceCaps(UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS8* pCaps);
HMONITOR APIENTRY GetAdapterMonitor(UINT Adapter);
HRESULT APIENTRY CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice8** ppReturnedDeviceInterface);
MyIDirect3D8(void);
IDirect3D8 * lpD3D;
IDirect3DDevice8 * lpD3DD8;
IDirect3DDevice8 * lpD3DD8bak;
ULONG m_count;
};
pGame就是我们的外挂的主类包括界面处理等等,在下一点讲解。
IpD3DDevice是Direct3DDevice8(D3D 设备) 的接口的指针,我们也要想办法解决,不急,等下慢慢说。
替换VTable其实很简单,我们只需要new一个我们自己的的MyIDirect3D8把老的IDirect3D8的指针内容直接替换就行了,呵呵:
//替换VTable,实现对IDirect3Draw 的 COM接口的挂钩
NewlpD3d = new MyIDirect3D8;
m = (IDirect3D8*)NewlpD3d;
Direct3DDevice8(D3D 设备) 的接口的指针是在IDirect3D8里面Create的我们再看看MyIDirect3D8的CreateDevice函数如何定义:
HRESULT APIENTRY MyIDirect3D8::CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice8** ppReturnedDeviceInterface)
{
static MyIDirect3DDevice8 * id3dd8 = NULL;
HRESULT m = lpD3D->CreateDevice(Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,ppReturnedDeviceInterface);
lpD3DD8 = *ppReturnedDeviceInterface;
//Hook IDirect3DDevice8
::ShowWindow(hFocusWindow,SW_HIDE);
lpD3D->CreateDevice(Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,&lpD3DD8bak);
::ShowWindow(hFocusWindow,SW_SHOW);
::SetFocus(hFocusWindow);
id3dd8 = new MyIDirect3DDevice8(lpD3DD8bak);
*ppReturnedDeviceInterface = (IDirect3DDevice8*)id3dd8;
return m;
}
至于::ShowWindow(hFocusWindow,SW_HIDE);初始化后::ShowWindow(hFocusWindow,SW_SHOW);保证进程不挂,呵呵。
IDirect3DDevice8要想得到IDirect3DDevice8的里面的内容,我们也采用同样方法的偷粱换柱子。MyIDirect3DDevice8定义就不再贴出来了,浪费页面。要解释下的地方是
HRESULT APIENTRY MyIDirect3DDevice8::BeginScene()
{
return g_pD3DDevice->BeginScene();
}
HRESULT APIENTRY MyIDirect3DDevice8::EndScene()
{
if(pGame!=NULL) pGame->Render();
return g_pD3DDevice->EndScene();
}
我们的画图函数按道理讲要放到BeginScene()之后,但是我们不是写自己的3D游戏,而是在做外挂,
程序是这么处理的:
别人调用BeginScene();
别人Render();
别人调用EndScene();
看看这个,我们把自己的pGame->Render();放到MyIDirect3DDevice8::BeginScene()里,结果就是自己的画图全被别人的图覆盖了,所有选择放到MyIDirect3DDevice8::EndScene()里去。
到这里我们从诸仙得到的东西已经能满足我们的需求了,那我们就专心的干我们的事情吧,做外挂界面吧。
4.游戏外挂界面处理类CGAME实现游戏外挂界面
做外挂自己做个UI,估计没那必要,所以要选个UI,这里我选的是CEGUI来实现的。解释之前先来看看CEGUI做出来的最终效果:
至于怎么没读出一些人物信息,没办法,我的诛仙版本是很久以前的,也懒得升级,无法登陆,在这里说明问题就行了。我的CGame定义如下:
#pragma once
#include
#include "d3dfont.h"
#include "d3dpanel.h"
#include
#include
#include
#pragma comment (lib, "d3d8.lib")
#pragma comment (lib, "d3dx8.lib")
#pragma comment (lib, "dxguid.lib")
#pragma comment (lib, "winmm.lib")
#define _DWORD(name,address);/
DWORD *##name;void _##name(void){##name = (DWORD *)(##address+BaseAddress);};
#define _WCHAR(name,address);/
wchar_t **##name;void _##name(void){##name = (wchar_t **)(##address+BaseAddress);};
#define _DOUBLE(name,address);/
double *##name;void _##name(void){##name = (double *)(##address+BaseAddress);};
#define INIT(ClassName) _##ClassName(DWORD _BaseAddress){BaseAddress = _BaseAddress;
#define _INIT }
#define init(name); _##name();
#define pHp 0x254 //生命值偏移
static DWORD BaseAddress = NULL;
static bool focusflag = false;
static int creatflag = 0;
static CEGUI::String creat_str="";
//全局函数
static void AsciiToUtf8(char * AsciiStr,char * Utf8Str)
{
//ascii转换成unicode
CStringW strw;
strw = CA2W(AsciiStr);
//unicode转换成UTF8
DWORD dwMinSize;
dwMinSize = WideCharToMultiByte(CP_UTF8, 0, strw, -1, 0,0,NULL,NULL);
WideCharToMultiByte(CP_UTF8,0,strw,-1,Utf8Str,dwMinSize,NULL,NULL);
}
//人物基本信息
class _HumInfo
{
public:
//定义人物基本信息值
_WCHAR( name, 0x3a4 );//角色名字
_DWORD( id, 0x240 );//角色ID
_DWORD( zy, 0x248 );//职业代码
_DWORD( lv, 0x24c );//等级
_DOUBLE(jy, 0x260 );//经验 double 8字节
_DWORD( hp, 0x254 );//生命
_DWORD( mp, 0x258 );//生命上限
_DWORD( hpmax, 0x26c );//真气
_DWORD( mpmax, 0x270 );//真气上限
_DWORD( skillmin, 0x2a4 );//最小攻击
_DWORD( skillmax, 0x2a8 );//最大攻击
_DWORD( fy, 0x2b0 );//防御
_DWORD( sd, 0x2b4 );//闪躲
_DWORD( si, 0x7b8 );//目标ID
_DWORD( gold, 0x2d4 );//金钱
_DOUBLE( x, 0x3dc );//x坐标
_DOUBLE( y, 0x3e0 );//y坐标
//初始化人物基本信息值
INIT(HumInfo)
init(name);
init(id);
init(zy);
init(lv);
init(jy);
init(hp);
init(mp);
init(hpmax);
init(mpmax);
init(skillmin);
init(skillmax);
init(fy);
init(sd);
init(si);
init(gold);
init(x);
init(y);
_INIT
};
//周围人物/怪物
static UINT GetBaseinfoProc(LPVOID pParam);
class CGame
{
public:
CGame(LPDIRECT3DDEVICE8 pD3DDevice);
~CGame(void);
void Render(void);
// 窗口消息处理
LRESULT WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam);
_HumInfo *huminfo;
struct BASEINFO //基本信息结构
{
unsigned long int baseadd;
unsigned long int base; //基地址
unsigned long int hummanbase; //人物基地址
}baseinfo;
CEGUI::Window *gameGUI;
private:
CD3DFont * pfont;
CD3DPanel * pPanel;
LPDIRECT3DDEVICE8 g_pD3DDevice;
D3DVIEWPORT8 Viewport;
CWinThread* hThread;
int s_W,s_H;
float m_rotateY;
CEGUI::DirectX81Renderer* myRenderer;
void Setup2DCamera(int W, int H);
void SetupGUI(void);
bool TurnLeft(const CEGUI::EventArgs& e);
bool TurnRight(const CEGUI::EventArgs& e);
bool DoubleClick(const CEGUI::EventArgs& e);
//关闭初始化窗口
bool CloseCreate(const CEGUI::EventArgs& e);
//初始化确定
bool CGame::OkCreate(const CEGUI::EventArgs& e);
bool GetHumanInfo(void);
// 获得基本信息
bool GetBaseInfo(void);
// 关闭人物信息窗口
bool CloseHumanInfo(const CEGUI::EventArgs& e);
// 打开人物信息窗口
bool OpenHumanInfo(const CEGUI::EventArgs& e);
public:
// //线程退出标志
bool mExitThread;
};
CEGUI在CGame里是怎么运行起来的呢?在CGame初始化的时候,我调用了里面的SetupGUI()这个函数,开始初始化CEGUI.SetupGUI()如下:
void CGame::SetupGUI(void)
{
/// 初始化GUI资源的缺省路径
myRenderer = new CEGUI::DirectX81Renderer(g_pD3DDevice,0);
new CEGUI::System(myRenderer);
CEGUI::DefaultResourceProvider* rp = static_cast
(CEGUI::System::getSingleton().getResourceProvider());
rp->setResourceGroupDirectory("schemes", "datafiles/schemes/");
rp->setResourceGroupDirectory("imagesets", "datafiles/imagesets/");
rp->setResourceGroupDirectory("fonts", "datafiles/fonts/");
rp->setResourceGroupDirectory("layouts", "datafiles/layouts/");
rp->setResourceGroupDirectory("looknfeels", "datafiles/looknfeel/");
//rp->setResourceGroupDirectory("lua_scripts", "../datafiles/lua_scripts/");
/// 设置使用的缺省资源
CEGUI::Imageset::setDefaultResourceGroup("imagesets");
CEGUI::Font::setDefaultResourceGroup("fonts");
CEGUI::Scheme::setDefaultResourceGroup("schemes");
CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
CEGUI::WindowManager::setDefaultResourceGroup("layouts");
//CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
/// 设置GUI
using namespace CEGUI;
/// 得到GUI样式的图片集
Imageset* taharezlookImage;
try{
taharezlookImage = ImagesetManager::getSingleton().createImageset("TaharezLook.imageset");
}catch (CEGUI::Exception& exc)
{
AfxMessageBox(exc.getMessage().c_str());
}
/// 设置鼠标图标
// System::getSingleton().setDefaultMouseCursor(&taharezlookImage->getImage("MouseArrow"));
/// 设置字体
FontManager::getSingleton().createFont("simhei-10.font");
/// 设置GUI皮肤
WidgetLookManager::getSingleton().parseLookNFeelSpecification("TaharezLook.looknfeel");
/// 载入GUI规划
SchemeManager::getSingleton().loadScheme("TaharezLook.scheme");
/// 得到窗口管理单件
CEGUI::WindowManager& winMgr = WindowManager::getSingleton();
/// 从layout文件中载入布局
gameGUI = winMgr.loadWindowLayout("TabControlDemo.layout");
/// 设置GUI的Sheet(Sheet是CEGUI中窗口的容器)
System::getSingleton().setGUISheet(gameGUI);
TabControl *tc = static_cast(winMgr.getWindow ("TabControlDemo/TabControl"));
// Add some pages to tab control
tc->addTab(winMgr.loadWindowLayout ("baseinfo.layout", "TabControlDemo/"));
tc->addTab(winMgr.loadWindowLayout ("TabPage1.layout", "TabControlDemo/"));
tc->addTab(winMgr.loadWindowLayout ("TabPage2.layout", "TabControlDemo/"));
//设置主界面
ImagesetManager::getSingleton().createImagesetFromImageFile("ImageHP", "hp.bmp");
ImagesetManager::getSingleton().createImagesetFromImageFile("ImageMP", "mp.bmp");
ImagesetManager::getSingleton().createImagesetFromImageFile("ImageFACE", "face.bmp");
ImagesetManager::getSingleton().createImagesetFromImageFile("ImagePick", "pick.bmp");
ImagesetManager::getSingleton().createImagesetFromImageFile("ImageAttack", "attack.bmp");
ImagesetManager::getSingleton().createImagesetFromImageFile("ImageDig", "dig.bmp");
ImagesetManager::getSingleton().createImagesetFromImageFile("ImageRepair", "Repair.bmp");
winMgr.getWindow("TabControlDemo/BaseInfo/ImageHp")->setProperty("Image","set:ImageHP image:full_image");
winMgr.getWindow("TabControlDemo/BaseInfo/ImageMp")->setProperty("Image","set:ImageMP image:full_image");
winMgr.getWindow("TabControlDemo/BaseInfo/Face")->setProperty("Image","set:ImageFACE image:full_image");
winMgr.getWindow("TabControlDemo/BaseInfo/Imagegold")->setProperty("Image","set:ImagePick image:full_image");
winMgr.getWindow("TabControlDemo/BaseInfo/attack")->setProperty("Image","set:ImageAttack image:full_image");
winMgr.getWindow("TabControlDemo/BaseInfo/attack1")->setProperty("Image","set:ImageRepair image:full_image");
winMgr.getWindow("TabControlDemo/BaseInfo/attack2")->setProperty("Image","set:ImageDig image:full_image");
MultiColumnList* mclbox = static_cast(winMgr.getWindow("TabControlDemo/BaseInfo/BagItem"));
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->addRow();
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,0);
mclbox->setItem(new MyListItem("10"),1,0);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,1);
mclbox->setItem(new MyListItem("10"),1,1);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,2);
mclbox->setItem(new MyListItem("10"),1,2);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,3);
mclbox->setItem(new MyListItem("10"),1,3);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,4);
mclbox->setItem(new MyListItem("10"),1,4);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,5);
mclbox->setItem(new MyListItem("10"),1,5);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,6);
mclbox->setItem(new MyListItem("10"),1,6);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,7);
mclbox->setItem(new MyListItem("10"),1,7);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,8);
mclbox->setItem(new MyListItem("10"),1,8);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,9);
mclbox->setItem(new MyListItem("10"),1,9);
mclbox->setItem(new MyListItem((CEGUI::utf8*)(LPCSTR)("狗皮膏药")),0,10);
mclbox->setItem(new MyListItem("10"),1,10);
winMgr.getWindow("TabControlDemo/")->hide();
winMgr.getWindow("GameGUI/Creat")->hide();
winMgr.getWindow("GameGUI/Creat/EDIT")->setText("100");
//建立事件监听
/// 设置鼠标事件自动重复
winMgr.getWindow("GameGUI/Button")->setWantsMultiClickEvents(false);
winMgr.getWindow("GameGUI/Button")->setMouseAutoRepeatEnabled(true);
//打开主窗口
winMgr.getWindow("GameGUI/Button")->subscribeEvent(
CEGUI::Window::EventMouseButtonDown,
CEGUI::Event::Subscriber(&CGame::TurnLeft, this));
//关闭主窗口
winMgr.getWindow("TabControlDemo/BaseInfo/Close")->subscribeEvent(
CEGUI::Window::EventMouseButtonDown,
CEGUI::Event::Subscriber(&CGame::TurnRight, this));
//关闭HUMANINFO窗口
// winMgr.getWindow("GameGUI/HumanInfo/Close")->subscribeEvent(
// CEGUI::Window::EventMouseButtonDown,
// CEGUI::Event::Subscriber(&CGame::CloseHumanInfo, this));
//打开HUMANINFO窗口
// winMgr.getWindow("GameGUI/Window//Item1/Item3")->subscribeEvent(
// CEGUI::Window::EventMouseButtonDown,
// CEGUI::Event::Subscriber(&CGame::OpenHumanInfo, this));
//关闭初始化窗口
winMgr.getWindow("GameGUI/Creat/CLOSE")->subscribeEvent(
CEGUI::Window::EventMouseButtonDown,
CEGUI::Event::Subscriber(&CGame::CloseCreate, this));
//初始化确定
winMgr.getWindow("GameGUI/Creat/OK")->subscribeEvent(
CEGUI::Window::EventMouseButtonDown,
CEGUI::Event::Subscriber(&CGame::OkCreate, this));
}
关于CEGUI不懂的还是老方法->google,我就不要讲太多了,现在太晚了,我还是快点写完睡觉。
这段程序里的解释也够多,我要讲的就是如何使CEGUI和诸仙的鼠标键盘事件联系起来和CEGUI如何和诸仙联系起来。
myRenderer = new CEGUI::DirectX81Renderer(g_pD3DDevice,0);这里CEGUI已经取得了D3D的设备接口了,只要在CGame的Render加入CEGUI的Render就行了,记住必须等你的CEGUI初始化完了你才开始CEGUI::System::getSingleton().renderGUI(),CGame的Render在前面已经运行去来了,不记得的大家到前面去看看)。程序如下:
void CGame::Render(void)
{
static DWORD m_dwFrames = 0;
static DWORD m_dwStartTime = timeGetTime();
char buffer[255];
DWORD dwDuration = (timeGetTime() - m_dwStartTime) / 1000;
if(dwDuration > 0)
{
sprintf(buffer, "TEST: %d seconds. Frames: %d. FPS: %d.", dwDuration, m_dwFrames, (m_dwFrames / dwDuration));
}
else
{
sprintf(buffer, "Calculating...");
}
pfont->DrawText(buffer, 3, 3, D3DCOLOR_XRGB(0, 0, 0 ));
pfont->DrawText(buffer, 3, 2, D3DCOLOR_XRGB(0, 0, 255));
CEGUI::System::getSingleton().renderGUI();
m_dwFrames++;
}
和诸仙的鼠标键盘事件联系起来看看下面一段你就明白了。
extern "C" void PASCAL EXPORT S_hWnd(void)
{
HWND shWnd = GetForegroundWindow();
Zx_OldWinFunc = SetWindowLong(shWnd,GWL_WNDPROC,(long)&WindowFunc);
//以下防止该线程过早结束,导致WindowFunc提前失效
while(1)
{
Sleep(3000);
}
}
//开始新的消息循环
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam)
{
if(pGame->WindowFunc(hwnd,message,wParam,lparam)) return ::CallWindowProc((WNDPROC)Zx_OldWinFunc,hwnd,message,wParam,lparam); //默认的消息交给原来的消息处理函数处理
else return 1;
}
// 窗口消息处理,让Game将窗口消息监听起来
LRESULT CGame::WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam)
{
switch(message)
{
case WM_MOUSEMOVE:
if(CEGUI::System::getSingleton().injectMousePosition(static_cast(LOWORD(lparam)), static_cast(HIWORD(lparam)))) return 0;
break;
case WM_LBUTTONDOWN:
if(CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton)) return 0;
break;
case WM_LBUTTONUP:
if(CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton)) return 0;
break;
case WM_CHAR:
if(wParam<48||wParam>57) break;
if(CEGUI::System::getSingleton().injectChar(wParam)) return 0;
break;
case WM_KEYDOWN:
if(CEGUI::System::getSingleton().injectKeyDown(static_cast(wParam))) return 0;
break;
case WM_KEYUP:
if(CEGUI::System::getSingleton().injectKeyUp(static_cast(wParam))) return 0;
break;
}
if(focusflag) return 0;
return 1;
}
写到这里,相信大家已经能够用这种方法在D3D游戏中能够真正的做出D3D窗口的外挂了,我也了了以前说的要给出方法的许诺。
时间仓促,写的不好,错误是肯定有的,有错误大家跟贴指正,不要骂人哈。
喜欢写点小程序的加我QQ:34187280 烂人哭吧