游戏环境下如何实现真正D3D的窗口

Home / Article MrLee 2016-11-2 3239

游戏环境下如何实现真正D3D的窗口(可以说外挂窗口哦!)

1.序
最近研究OGRE引擎时用CEGUI做游戏UI时想出来的,以前用MFC做了在别的程序中监听的效果,后来看到在3D中用D3D可以做出
3D的效果,在加上CEGUI可以把画面做的更漂亮些。
 
 
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,不做详细的解释,实在搞不懂就baidu(俺也是这么得来的:))。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 <d3d8.h> #include "d3dfont.h" #include "d3dpanel.h" #include <d3dx8.h> #include <mmsystem.h> #include <RendererModules/directx81GUIRenderer/renderer.h>
#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::DefaultResourceProvider*> (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<TabControl *>(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<MultiColumnList*>(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不懂的还是老方法->baidu,我就不要讲太多了.
这段程序里的解释也够多,我要讲的就是如何使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<float>(LOWORD(lparam)), static_cast<float>(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<unsigned int>(wParam))) return 0; break; case WM_KEYUP: if(CEGUI::System::getSingleton().injectKeyUp(static_cast<unsigned int>(wParam))) return 0; break; } if(focusflag) return 0; return 1; }
写到这里,相信大家已经能够用这种方法在D3D游戏中能够真正的做出D3D窗口的外挂了,我也了了以前说的要给出方法的许诺。 时间仓促,写的不好,错误是肯定有的,有错误大家跟贴指正,不要骂人哈。 最近还是研究游戏引擎时想出来的。有问题可以给我留言!

本文链接:https://www.it72.com/11181.htm

推荐阅读
最新回复 (0)
返回