ImGUI 它是与平台无关的C++轻量级跨平台图形界面库,没有任何第三方依赖,可以将ImGUI的源码直接加到项目中使用,该框架通常会配合特定的D3Dx9等图形开发工具包一起使用,ImGUI常用来实现进程内的菜单功能,而有些辅助开发作者也会使用该框架开发菜单页面,总体来说这是一个很不错的绘图库,如下将公开新版ImGUI如何实现绘制外部菜单的功能。
ImGUI官方下载地址:https://github.com/ocornut/imgui/releases
在使用ImGUI页面之前需要先来实现一个简单的附着功能,即如何将一个窗体附着到另一个窗体之上,其实代码很简单,如下所示当用户输入进程PID时,会自动跟随窗体并附着在窗体顶部。
#include <Windows.h>
#include <iostream>
struct handle_data
{
unsigned long process_id;
HWND best_handle;
};
// By: LyShark
BOOL IsMainWindow(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
// By: LyShark
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !IsMainWindow(handle)) {
return TRUE;
}
data.best_handle = handle;
return FALSE;
}
// By: LyShark
HWND FindMainWindow(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
data.best_handle = 0;
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
return data.best_handle;
}
int main(int argc, char* argv[])
{
DWORD pid = 28396;
std::cout << "输入进程PID: " << std::endl;
std::cin >> pid;
// 获取屏幕宽和高
int iWidth = ::GetSystemMetrics(SM_CXSCREEN);
int iHeight = ::GetSystemMetrics(SM_CYSCREEN);
// 根据PID寻找游戏窗口
HWND hwnd = FindMainWindow(pid);
while (1)
{
SetTimer(hwnd, 1, 150, NULL);
// 实现透明必须设置WS_EX_LAYERED标志
LONG lWinStyleEx = GetWindowLong(hwnd, GWL_EXSTYLE);
lWinStyleEx = lWinStyleEx | WS_EX_LAYERED;
SetWindowLong(hwnd, GWL_EXSTYLE, lWinStyleEx);
SetLayeredWindowAttributes(hwnd, 0, RGB(40, 40, 40), LWA_ALPHA);
// 去掉标题栏及边框
LONG_PTR Style = GetWindowLongPtr(hwnd, GWL_STYLE);
Style = Style & ~WS_CAPTION & ~WS_SYSMENU & ~WS_SIZEBOX;
SetWindowLongPtr(hwnd, GWL_STYLE, Style);
// 至顶层窗口 最大化
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, iWidth, iHeight, SWP_SHOWWINDOW);
// 设置窗体可穿透鼠标
SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED);
// 绘图
HDC hdc = ::GetDC(hwnd);
HDC mdc = ::CreateCompatibleDC(hdc);
// 创建画笔
HPEN hpen = CreatePen(PS_SOLID, 10, RGB(0, 255, 0));
// DC 选择画笔
SelectObject(hdc, hpen);
// (画笔)从初始点移动到 50,50
MoveToEx(hdc, 100, 100, NULL);
// (画笔)从初始点画线到 100,100
LineTo(hdc, 1000, 1000);
RECT rect = {0};
rect.bottom = 10;
rect.left = 20;
rect.right = 20;
rect.top = 15;
DrawText(hdc, L"hello lyshark.com", strlen("hello lyshark.com"), &rect, DT_CALCRECT | DT_CENTER | DT_SINGLELINE);
}
return 0;
}
绘制效果图:
接着我们使用Imgui绘制一个动态菜单,首先下载imgui并打开项目中的examples
目录,找到example_win32_directx9
打开后自己配置好dx9SDK
开发工具包。
代码直接调用,并附加到Counter-Strike Source
游戏窗体之上即可,这段代码也很简单。
#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h"
#include <d3d9.h>
#include <tchar.h>
#include <iostream>
#pragma execution_character_set("utf-8")
// 全局变量
// lyshark.com
static HWND hwnd;
static HWND GameHwnd;
static RECT WindowRectangle;
static int WindowWide, WindowHeight;
static LPDIRECT3D9 g_pD3D = NULL;
static LPDIRECT