諸仙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窗口的外掛了,我也了了以
前說的要給出方法的許諾。
時間倉促,寫的不好,錯誤是肯定有的,有錯誤大家跟貼指正,不要罵人哈。