您的位置:首页 > 其它

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

2013-05-08 15:37 337 查看
诸仙D3D游戏环境下如何实现真正D3D的窗口,给出关键代码及其方法(希望大家在D3

D游戏中做出D3D窗口)!

前些日子一直忙,也没来看看,说要给出代码和方法的一直没有给出来请大家见谅,今天给出来!

声明:我不是做游戏外挂的,所以对外挂部分还比较薄弱,没做,只做实现窗口这一块!

1.先看实现的图片,等下慢慢解释。

2.首先解释要如何启动诸仙的进程。

我们要想拥有自己的窗口,那么就必须在诸仙的进程启动之前得到Direct3DCreate8接口(诸仙用Direct

3D8)。所以启动过程如下:

//启动诸仙并获取诸仙进程句柄

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类型,这个类主要是打开进程和取得进程的一些信息,GetPr

ocess()取的改进程的句柄。这个类里面要解释下的是:

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_REA

DWRITE);

::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, lpRemote

DllName, 0, NULL);

if(hRemoteThread == NULL)

{

::CloseHandle(hProcess);

return FALSE;

}

::CloseHandle(hRemoteThread);

return TRUE;

}

这段关键是在:

// 启动远程线程

::ResumeThread(ZhuXianProc.GetThread());

HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemote

DllName, 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给变成了新的入口地址NewDirect3DCreat

e8了,那么当诸仙运行的时候这个函数就跑到我们的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 HO

OK 获得Direct3DDevice8(D3D 设备) 的接口的指针从而得到我们的Render该放到什么地方。

COM HOOK其实就是写一个同样的类用来替换COM的VTable,不做详细的解释,实在搞不懂就googl

e(俺也是这么得来的:))。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_IDENTI

FIER8* pIdentifier);

UINT APIENTRY GetAdapterModeCount(UINT Adapter);

HRESULT APIENTRY EnumAdapterModes(UINT Adapter,UINT Mode,D3DDISPLAYMODE* pMo

de);

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,D3DFORM

AT 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,D3DF

ORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat);

HRESULT APIENTRY GetDeviceCaps(UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS8* p

Caps);

HMONITOR APIENTRY GetAdapterMonitor(UINT Adapter);

HRESULT APIENTRY CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWi

ndow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDe

vice8** 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的C

reateDevice函数如何定义:

HRESULT APIENTRY MyIDirect3D8::CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,HWND

hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,I

Direct3DDevice8** ppReturnedDeviceInterface)

{

static MyIDirect3DDevice8 * id3dd8 = NULL;

HRESULT m = lpD3D->CreateDevice(Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresen

tationParameters,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的里面的内容,我们也采用同样方法的偷粱换柱子。MyIDir

ect3DDevice8定义就不再贴出来了,浪费页面。要解释下的地方是

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不懂的还是老方法->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<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窗口的外挂了,我也了了以

前说的要给出方法的许诺。

时间仓促,写的不好,错误是肯定有的,有错误大家跟贴指正,不要骂人哈。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: